namespace ZB.MOM.WW.ScadaBridge.DelmiaNotifier;

internal static class Program
{
    /// <summary>Entry point: loads config, sends the recipe-download notification with failover across the configured base URLs, and reports the legacy YES/NO stdout contract.</summary>
    /// <param name="args">Command-line arguments parsed into the recipe download payload.</param>
    /// <returns>A task that resolves to the process exit code.</returns>
    public static async Task<int> Main(string[] args)
    {
        var stdout = Console.Out;

        // Config first, so the diagnostic log can honour the configured LogPath even for early failures.
        NotifierConfig cfg;
        try
        {
            cfg = ConfigLoader.LoadFromDefaultFile();
        }
        catch (Exception ex)
        {
            new DiagLog(null).Write("config load failed: " + ex.Message);
            return Reporter.Report(false, "config load failed: " + ex.Message, stdout);
        }

        var log = new DiagLog(cfg.ScadaBridge.LogPath);

        try
        {
            var parse = ArgParser.Parse(args);
            if (!parse.Ok)
            {
                log.Write("arg error: " + parse.Error);
                return Reporter.Report(false, parse.Error!, stdout);
            }

            var baseUrls = ConfigLoader.SplitBaseUrls(cfg.ScadaBridge.BaseUrls);
            if (baseUrls.Length == 0)
            {
                log.Write("no BaseUrls configured");
                return Reporter.Report(false, "no BaseUrls configured", stdout);
            }

            var apiKey = ConfigLoader.ResolveApiKey(Environment.GetEnvironmentVariable);
            if (apiKey is null)
            {
                log.Write("API key not configured (SCADABRIDGE_API_KEY)");
                return Reporter.Report(false, "API key not configured (SCADABRIDGE_API_KEY)", stdout);
            }

            using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(cfg.ScadaBridge.TimeoutSeconds) };
            var sender = new LoggingRecipeSender(new HttpRecipeSender(http, apiKey), log);

            log.Write($"notifying {baseUrls.Length} URL(s) for machine {parse.Payload!.MachineCode}");
            var result = await Notifier.RunAsync(baseUrls, parse.Payload, sender, CancellationToken.None);
            log.Write($"result: ok={result.Ok} reason={result.Reason}");
            return Reporter.Report(result.Ok, result.Reason, stdout);
        }
        catch (Exception ex)
        {
            log.Write("unexpected error: " + ex);
            return Reporter.Report(false, "unexpected error: " + ex.Message, stdout);
        }
    }

    /// <summary>Decorates a sender to emit a per-attempt diagnostic line; keeps stdout reserved for the YES/NO contract.</summary>
    private sealed class LoggingRecipeSender(IRecipeSender inner, DiagLog log) : IRecipeSender
    {
        /// <inheritdoc />
        public async Task<AttemptOutcome> SendAsync(string baseUrl, RecipeDownload payload, CancellationToken ct)
        {
            var outcome = await inner.SendAsync(baseUrl, payload, ct);
            log.Write(outcome.Kind == AttemptKind.ConnectFailed
                ? $"attempt {baseUrl}: connect failed: {outcome.Error}"
                : $"attempt {baseUrl}: HTTP {outcome.StatusCode}");
            return outcome;
        }
    }
}
