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

namespace BrassAndSigil.Server.Commands;

public sealed class InstallCommand : AsyncCommand<InstallCommand.Settings>
{
    public sealed class Settings : BaseCommandSettings
    {
        [CommandOption("--manifest <URL>")]
        [Description("Manifest URL to bootstrap from")]
        public string? ManifestUrl { get; set; }

        [CommandOption("--server-dir <PATH>")]
        [Description("Where to install the server (defaults to ./server)")]
        public string? ServerDir { get; set; }

        [CommandOption("--memory <MB>")]
        [Description("RAM allocation in MB (defaults to 8192)")]
        public int? MemoryMB { get; set; }

        [CommandOption("--accept-eula")]
        [Description("Accept the Minecraft EULA. Required for the server to actually run.")]
        public bool AcceptEula { get; set; }
    }

    public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
    {
        var config = ServerConfig.Load(settings.ConfigPath);
        if (settings.ManifestUrl != null) config.ManifestUrl = settings.ManifestUrl;
        if (settings.ServerDir   != null) config.ServerDir   = settings.ServerDir;
        if (settings.MemoryMB    != null) config.MemoryMB    = settings.MemoryMB.Value;
        if (settings.AcceptEula)          config.AcceptEula  = true;

        AnsiConsole.MarkupLine("[bold yellow]Brass & Sigil Server install[/]");
        AnsiConsole.MarkupLine($"  Config:    {settings.ConfigPath}");
        AnsiConsole.MarkupLine($"  ServerDir: {Path.GetFullPath(config.ServerDir)}");
        AnsiConsole.MarkupLine($"  Manifest:  {config.ManifestUrl}");
        AnsiConsole.MarkupLine($"  Memory:    {config.MemoryMB} MB");
        AnsiConsole.MarkupLine("");

        if (!config.AcceptEula)
        {
            AnsiConsole.MarkupLine("[red]EULA not accepted.[/] Re-run with --accept-eula to confirm you accept the");
            AnsiConsole.MarkupLine("Minecraft End User License Agreement: [blue]https://aka.ms/MinecraftEULA[/]");
            return 1;
        }

        Directory.CreateDirectory(config.ServerDir);

        // Generate eula.txt
        await File.WriteAllTextAsync(
            Path.Combine(config.ServerDir, "eula.txt"),
            $"# Generated by brass-sigil-server install\n" +
            $"# By setting this to true you agree to the Minecraft EULA: https://aka.ms/MinecraftEULA\n" +
            $"eula=true\n");

        // Generate a default server.properties if none exists yet
        var propsPath = Path.Combine(config.ServerDir, "server.properties");
        if (!File.Exists(propsPath))
        {
            await File.WriteAllTextAsync(propsPath, DefaultServerProperties(config));
            AnsiConsole.MarkupLine($"[grey]Wrote default server.properties[/]");
        }

        // Generate a random RCON password if missing
        if (string.IsNullOrEmpty(config.RconPassword))
        {
            config.RconPassword = Convert.ToHexString(Guid.NewGuid().ToByteArray()).ToLowerInvariant();
            UpdateProp(propsPath, "enable-rcon", "true");
            UpdateProp(propsPath, "rcon.port", config.RconPort.ToString());
            UpdateProp(propsPath, "rcon.password", config.RconPassword);
        }

        // Save config
        config.Save(settings.ConfigPath);
        AnsiConsole.MarkupLine($"[grey]Saved config to {settings.ConfigPath}[/]");

        // Sync mods
        AnsiConsole.MarkupLine("");
        AnsiConsole.MarkupLine("[bold]Syncing mods from manifest...[/]");
        var sync = new ManifestSync();
        var progress = new Progress<string>(msg => AnsiConsole.MarkupLine($"  [grey]{msg.EscapeMarkup()}[/]"));
        try
        {
            var result = await sync.SyncAsync(config.ManifestUrl, config.ServerDir, progress);
            AnsiConsole.MarkupLine("");
            AnsiConsole.MarkupLine($"[green]✓ Sync complete:[/] pack v{result.PackVersion}, " +
                                   $"{result.Downloaded} downloaded, {result.Removed} removed, " +
                                   $"{result.Skipped} client-only mods skipped");
        }
        catch (Exception ex)
        {
            AnsiConsole.MarkupLine($"[red]✗ Sync failed:[/] {ex.Message.EscapeMarkup()}");
            return 1;
        }

        AnsiConsole.MarkupLine("");
        AnsiConsole.MarkupLine("[bold green]Install complete.[/]");
        AnsiConsole.MarkupLine("Next steps:");
        AnsiConsole.MarkupLine($"  1. Download the matching NeoForge server installer for the manifest's loader version");
        AnsiConsole.MarkupLine($"     (server side, into {Path.GetFullPath(config.ServerDir)}) -- the modpack manifest");
        AnsiConsole.MarkupLine($"     doesn't bundle it because each loader has its own installer.");
        AnsiConsole.MarkupLine($"     [blue]https://maven.neoforged.net/releases/net/neoforged/neoforge/[/]");
        AnsiConsole.MarkupLine($"  2. Run the NeoForge installer with --installServer in the server dir");
        AnsiConsole.MarkupLine($"  3. Then start: [yellow]brass-sigil-server run[/]");
        return 0;
    }

    private static string DefaultServerProperties(ServerConfig config) => $@"# Brass & Sigil server defaults -- edit as needed
motd=Brass & Sigil
gamemode=survival
difficulty=normal
hardcore=false
pvp=true
online-mode=true
white-list=true
enforce-whitelist=true
max-players=20
view-distance=12
simulation-distance=10
spawn-protection=0
enable-rcon=true
rcon.port={config.RconPort}
rcon.password={config.RconPassword}
broadcast-rcon-to-ops=false
";

    private static void UpdateProp(string path, string key, string value)
    {
        var lines = File.ReadAllLines(path).ToList();
        var prefix = $"{key}=";
        var idx = lines.FindIndex(l => l.StartsWith(prefix));
        if (idx >= 0) lines[idx] = prefix + value;
        else lines.Add(prefix + value);
        File.WriteAllLines(path, lines);
    }
}
