using System.Diagnostics;
using BrassAndSigil.Server.Models;
using BrassAndSigil.Server.Services;
using Spectre.Console;
using Spectre.Console.Cli;

namespace BrassAndSigil.Server.Commands;

public sealed class CheckCommand : AsyncCommand<BaseCommandSettings>
{
    public override async Task<int> ExecuteAsync(CommandContext context, BaseCommandSettings settings)
    {
        var config = ServerConfig.Load(settings.ConfigPath);
        AnsiConsole.MarkupLine("[bold]Checking server install...[/]");
        var ok = true;

        // 1. Java available?
        var javaVersion = await TryRunForOutputAsync(config.JavaPath, "-version");
        if (javaVersion is not null)
            AnsiConsole.MarkupLine($"  [green]✓[/] Java reachable: {javaVersion.Split('\n')[0].Trim().EscapeMarkup()}");
        else
        { AnsiConsole.MarkupLine($"  [red]✗[/] Java not found at '{config.JavaPath}'"); ok = false; }

        // 2. Server dir
        var serverDir = Path.GetFullPath(config.ServerDir);
        if (Directory.Exists(serverDir))
            AnsiConsole.MarkupLine($"  [green]✓[/] Server dir exists: {serverDir}");
        else
        { AnsiConsole.MarkupLine($"  [yellow]?[/] Server dir missing -- run [yellow]install[/] first"); ok = false; }

        // 3. EULA
        var eulaPath = Path.Combine(serverDir, "eula.txt");
        if (File.Exists(eulaPath) && File.ReadAllText(eulaPath).Contains("eula=true"))
            AnsiConsole.MarkupLine("  [green]✓[/] EULA accepted");
        else
        { AnsiConsole.MarkupLine("  [yellow]?[/] EULA not accepted (re-run [yellow]install --accept-eula[/])"); ok = false; }

        // 4. NeoForge run script
        var runScript = Path.Combine(serverDir, OperatingSystem.IsWindows() ? "run.bat" : "run.sh");
        if (File.Exists(runScript))
            AnsiConsole.MarkupLine($"  [green]✓[/] Loader start script: {Path.GetFileName(runScript)}");
        else
            AnsiConsole.MarkupLine($"  [yellow]?[/] No {Path.GetFileName(runScript)} -- install the NeoForge server first");

        // 5. Manifest reachable
        try
        {
            using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
            var resp = await http.GetAsync(config.ManifestUrl);
            if (resp.IsSuccessStatusCode)
                AnsiConsole.MarkupLine($"  [green]✓[/] Manifest reachable: {config.ManifestUrl}");
            else
            { AnsiConsole.MarkupLine($"  [red]✗[/] Manifest HTTP {(int)resp.StatusCode}: {config.ManifestUrl}"); ok = false; }
        }
        catch (Exception ex)
        { AnsiConsole.MarkupLine($"  [red]✗[/] Manifest fetch error: {ex.Message.EscapeMarkup()}"); ok = false; }

        // 6. Pack version on disk
        var packVer = Path.Combine(serverDir, "pack-version.json");
        if (File.Exists(packVer))
            AnsiConsole.MarkupLine($"  [green]✓[/] Pack synced: {File.ReadAllText(packVer).Replace("\n", " ").Replace("\r", "").Trim().EscapeMarkup()}");
        else
            AnsiConsole.MarkupLine("  [yellow]?[/] Pack not synced yet (run [yellow]sync[/])");

        AnsiConsole.MarkupLine("");
        AnsiConsole.MarkupLine(ok ? "[green]All required checks passed.[/]" : "[yellow]Some checks failed; see above.[/]");
        return ok ? 0 : 1;
    }

    private static async Task<string?> TryRunForOutputAsync(string fileName, string args)
    {
        try
        {
            var p = Process.Start(new ProcessStartInfo
            {
                FileName = fileName,
                Arguments = args,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            });
            if (p is null) return null;
            var output = await p.StandardError.ReadToEndAsync() + await p.StandardOutput.ReadToEndAsync();
            await p.WaitForExitAsync();
            return output;
        }
        catch { return null; }
    }
}
