using System.Globalization;

namespace LanMountainDesktop.Launcher;

internal sealed class CommandContext
{
    public const string AirAppBrokerCommand = "air-app-broker";

    private const string LaunchSourceOptionName = "launch-source";

    private static readonly string[] GuiCommands =
    [
        "launch",
        AirAppBrokerCommand,
        "apply-update",
        "preview-splash",
        "preview-error",
        "preview-update",
        "preview-oobe",
        "preview-debug"
    ];

    public string Command { get; }

    public string SubCommand { get; }

    public IReadOnlyDictionary<string, string> Options { get; }

    /// <summary>
    /// 原始命令行参数，用于转发给主程序
    /// </summary>
    public IReadOnlyList<string> RawArgs { get; }

    public bool IsLegacyPluginInstall =>
        Options.ContainsKey("source") &&
        Options.ContainsKey("plugins-dir") &&
        Options.ContainsKey("result");

    public string LaunchSource => NormalizeLaunchSource(GetOption(LaunchSourceOptionName)) ?? InferLaunchSource();

    /// <summary>
    /// 是否处于调试模式（从 Rider/VS 等 IDE 启动）
    /// 当满足以下任一条件时启用：
    /// 1. 明确指定 --debug 参数
    /// 2. 调试器附加（Debugger.IsAttached）
    /// 3. DOTNET_ENVIRONMENT 环境变量为 Development（IDE 调试启动时自动设置）
    /// </summary>
    public bool IsDebugMode =>
        Options.ContainsKey("debug") ||
        System.Diagnostics.Debugger.IsAttached ||
        IsDevelopmentEnvironment;

    /// <summary>
    /// 是否为 Development 环境（DOTNET_ENVIRONMENT=Development）
    /// Rider/VS 调试启动时会自动设置此环境变量
    /// </summary>
    public bool IsDevelopmentEnvironment =>
        string.Equals(
            System.Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"),
            "Development",
            StringComparison.OrdinalIgnoreCase);

    public bool IsPreviewCommand =>
        Command.StartsWith("preview-", StringComparison.OrdinalIgnoreCase);

    public bool IsAirAppBrokerCommand =>
        string.Equals(Command, AirAppBrokerCommand, StringComparison.OrdinalIgnoreCase);

    public bool IsGuiCommand =>
        GuiCommands.Contains(Command, StringComparer.OrdinalIgnoreCase);

    public bool IsMaintenanceCommand =>
        string.Equals(LaunchSource, "apply-update", StringComparison.OrdinalIgnoreCase) ||
        string.Equals(LaunchSource, "plugin-install", StringComparison.OrdinalIgnoreCase) ||
        string.Equals(Command, "update", StringComparison.OrdinalIgnoreCase) ||
        string.Equals(Command, "plugin", StringComparison.OrdinalIgnoreCase);

    public string? ExplicitAppRoot => GetOption("app-root");

    private CommandContext(string command, string subCommand, Dictionary<string, string> options, string[] rawArgs)
    {
        Command = command;
        SubCommand = subCommand;
        Options = options;
        RawArgs = rawArgs;
    }

    public static CommandContext FromArgs(string[] args)
    {
        var options = ParseOptions(args);
        var command = args.Length > 0 && !args[0].StartsWith("--", StringComparison.Ordinal)
            ? args[0]
            : "launch";
        var subCommand = args.Length > 1 && !args[1].StartsWith("--", StringComparison.Ordinal)
            ? args[1]
            : string.Empty;

        return new CommandContext(command, subCommand, options, args);
    }

    public string? GetOption(string key)
    {
        return Options.TryGetValue(key, out var value) ? value : null;
    }

    public int GetIntOption(string key, int fallback)
    {
        var raw = GetOption(key);
        return int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)
            ? value
            : fallback;
    }

    private string InferLaunchSource()
    {
        if (IsPreviewCommand)
        {
            return "debug-preview";
        }

        if (string.Equals(Command, "apply-update", StringComparison.OrdinalIgnoreCase))
        {
            return "apply-update";
        }

        if (IsLegacyPluginInstall || string.Equals(Command, "plugin", StringComparison.OrdinalIgnoreCase))
        {
            return "plugin-install";
        }

        return "normal";
    }

    private static string? NormalizeLaunchSource(string? raw)
    {
        if (string.IsNullOrWhiteSpace(raw))
        {
            return null;
        }

        return raw.Trim().ToLowerInvariant() switch
        {
            "normal" => "normal",
            "restart" => "restart",
            "postinstall" => "postinstall",
            "apply-update" => "apply-update",
            "plugin-install" => "plugin-install",
            "debug-preview" => "debug-preview",
            _ => null
        };
    }

    private static Dictionary<string, string> ParseOptions(string[] args)
    {
        var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        for (var i = 0; i < args.Length; i++)
        {
            var current = args[i];
            if (!current.StartsWith("--", StringComparison.Ordinal))
            {
                continue;
            }

            var key = current[2..];
            if (string.IsNullOrWhiteSpace(key))
            {
                continue;
            }

            var equalsIndex = key.IndexOf('=');
            if (equalsIndex >= 0)
            {
                values[key[..equalsIndex]] = key[(equalsIndex + 1)..];
                continue;
            }

            if (i + 1 < args.Length && !args[i + 1].StartsWith("--", StringComparison.Ordinal))
            {
                values[key] = args[++i];
                continue;
            }

            values[key] = "true";
        }

        return values;
    }
}
