using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Tests.Helpers;

public static class LocalServer
{
    private static Process? _process;
    public static string? BaseUrl { get; private set; }

    public static async Task StartAsync()
    {
        if (_process != null) return;

        var root = FindProjectRoot();
        var webProject = Path.Combine(root, "Web");

        Console.WriteLine($"[DEBUG_LOG] Starting local server for project: {webProject}");

        _process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "dotnet",
                Arguments = $"run --project \"{webProject}\" --urls http://127.0.0.1:0",
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                WorkingDirectory = root
            }
        };

        var tcs = new TaskCompletionSource<string>();

        _process.OutputDataReceived += (s, e) =>
        {
            if (string.IsNullOrEmpty(e.Data)) return;
            Console.WriteLine($"[SERVER] {e.Data}");
            var match = Regex.Match(e.Data, @"Now listening on:\s+(http://127.0.0.1:\d+)");
            if (match.Success) tcs.TrySetResult(match.Groups[1].Value);
        };

        _process.ErrorDataReceived += (s, e) =>
        {
            if (!string.IsNullOrEmpty(e.Data))
                Console.Error.WriteLine($"[SERVER ERROR] {e.Data}");
        };

        _process.Start();
        _process.BeginOutputReadLine();
        _process.BeginErrorReadLine();

        // Wait for the URL to be parsed from output
        BaseUrl = await Task.WhenAny(tcs.Task, Task.Delay(30000)) == tcs.Task
            ? tcs.Task.Result
            : null;

        if (BaseUrl == null)
        {
            Stop();
            throw new Exception("Timeout waiting for local server to start and provide a URL.");
        }

        Console.WriteLine($"[DEBUG_LOG] Local server started at: {BaseUrl}");
    }

    public static void Stop()
    {
        if (_process != null && !_process.HasExited)
        {
            Console.WriteLine("[DEBUG_LOG] Stopping local server...");
            _process.Kill(true);
            _process.Dispose();
            _process = null;
        }
    }

    private static string FindProjectRoot()
    {
        var current = AppDomain.CurrentDomain.BaseDirectory;
        while (!string.IsNullOrEmpty(current) && !File.Exists(Path.Combine(current, "IGP.sln")))
        {
            var parent = Path.GetDirectoryName(current);
            if (parent == current) break;
            current = parent;
        }

        if (string.IsNullOrEmpty(current) || !File.Exists(Path.Combine(current, "IGP.sln")))
        {
            // Fallback to searching up from current directory if BaseDirectory fails
            current = Directory.GetCurrentDirectory();
            while (!string.IsNullOrEmpty(current) && !File.Exists(Path.Combine(current, "IGP.sln")))
            {
                var parent = Path.GetDirectoryName(current);
                if (parent == current) break;
                current = parent;
            }
        }

        return current ?? throw new Exception("Could not find project root containing IGP.sln");
    }
}