using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Text.Json;

namespace NexusShell.Services;

/// <summary>
/// Ensures the local Nexus Identity API is running before login (laptop POC layout).
/// </summary>
public static class IdentityHostService
{
    public const string DefaultAuthority = "http://localhost:5050";

    private static Process? _identityProcess;

    public static void StopRunning() => StopTrackedProcess();

    public static async Task<(bool Ready, string? Error)> EnsureRunningAsync(
        string authority = DefaultAuthority,
        IProgress<string>? progress = null,
        CancellationToken cancellationToken = default)
    {
        if (await IsHealthyAsync(authority, cancellationToken))
        {
            return (true, null);
        }

        if (!NexusInstallRoot.TryResolve(out var installRoot))
        {
            return (false,
                "Identity API kører ikke. Start via NexusSetup.exe → 'Start Ninja Nexus', eller kør START-NEXUS-SAFE-MODE.ps1.");
        }

        var identityExe = Path.Combine(installRoot, "identity", "NexusIdentity.Api.exe");
        if (!File.Exists(identityExe))
        {
            return (false, "Nexus Identity mangler i installationsmappen.");
        }

        progress?.Report("Starter Identity API…");

        try
        {
            StopTrackedProcess();
            var logsDir = Path.Combine(installRoot, "logs");
            Directory.CreateDirectory(logsDir);

            var dbConnection = NexusIdentityDataPaths.BuildConnectionString(installRoot);
            var psi = new ProcessStartInfo
            {
                FileName = identityExe,
                WorkingDirectory = Path.GetDirectoryName(identityExe)!,
                Arguments = $"--urls {authority}",
                UseShellExecute = false,
                CreateNoWindow = true,
            };
            psi.Environment["NEXUS_DB_CONNECTION"] = dbConnection;

            _identityProcess = Process.Start(psi);
            if (_identityProcess is null)
            {
                return (false, "Kunne ikke starte Nexus Identity API.");
            }

            for (var i = 0; i < 30; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (_identityProcess.HasExited)
                {
                    var errLog = Path.Combine(logsDir, "identity.err.log");
                    var detail = File.Exists(errLog) ? await File.ReadAllTextAsync(errLog, cancellationToken) : "";
                    return (false,
                        "Identity API stopped. Installér .NET 8 ASP.NET Core Runtime." +
                        (string.IsNullOrWhiteSpace(detail) ? "" : $"\n{detail}"));
                }

                if (await IsHealthyAsync(authority, cancellationToken))
                {
                    progress?.Report("Identity API kører.");
                    return (true, null);
                }

                await Task.Delay(1000, cancellationToken);
            }

            return (false, "Identity API svarede ikke på /health (localhost:5050).");
        }
        catch (Exception ex) when (ex is not OperationCanceledException)
        {
            return (false, ex.Message);
        }
    }

    private static async Task<bool> IsHealthyAsync(string authority, CancellationToken cancellationToken)
    {
        try
        {
            using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(3) };
            var json = await client.GetStringAsync($"{authority.TrimEnd('/')}/health", cancellationToken);
            using var doc = JsonDocument.Parse(json);
            return doc.RootElement.TryGetProperty("status", out var status)
                && status.GetString() == "healthy";
        }
        catch
        {
            return false;
        }
    }

    private static void StopTrackedProcess()
    {
        if (_identityProcess is { HasExited: false })
        {
            try
            {
                _identityProcess.Kill(entireProcessTree: true);
                _identityProcess.WaitForExit(3000);
            }
            catch
            {
                // ignore
            }
        }

        _identityProcess = null;
    }
}
