namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Deployment;

/// <summary>
/// Fetches a deployment's flattened config JSON from central over HTTP
/// (notify-and-fetch). The site calls this after receiving a small notify.
/// </summary>
public interface IDeploymentConfigFetcher
{
    /// <summary>
    /// GETs the flattened config JSON for <paramref name="deploymentId"/> from
    /// <paramref name="centralFetchBaseUrl"/>, presenting <paramref name="token"/>
    /// in the X-Deployment-Token header. Throws <see cref="DeploymentConfigFetchException"/>
    /// on any non-success; a 404 (expired/superseded/unknown) sets IsSuperseded.
    /// </summary>
    /// <param name="centralFetchBaseUrl">Base URL of the central fetch endpoint.</param>
    /// <param name="deploymentId">Identifier of the deployment whose flattened config is being fetched.</param>
    /// <param name="token">Deployment token presented in the X-Deployment-Token header.</param>
    /// <param name="ct">Cancellation token for the request.</param>
    /// <returns>The flattened config JSON for the requested deployment.</returns>
    Task<string> FetchAsync(string centralFetchBaseUrl, string deploymentId, string token, CancellationToken ct);
}

/// <summary>Raised when a deployment-config fetch fails. <see cref="IsSuperseded"/> is true on HTTP 404.</summary>
public sealed class DeploymentConfigFetchException : Exception
{
    /// <summary>Gets a value indicating whether the fetch failed because the deployment was expired, superseded, or unknown (HTTP 404).</summary>
    public bool IsSuperseded { get; }

    /// <summary>Initializes a new instance of the <see cref="DeploymentConfigFetchException"/> class.</summary>
    /// <param name="message">The error message.</param>
    /// <param name="isSuperseded">Whether the failure was caused by an expired, superseded, or unknown deployment (HTTP 404).</param>
    /// <param name="inner">The underlying exception, if any.</param>
    public DeploymentConfigFetchException(string message, bool isSuperseded, Exception? inner = null)
        : base(message, inner) => IsSuperseded = isSuperseded;
}
