using System.Diagnostics;
using System.Text.RegularExpressions;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L28-1: winget 앱 검색·설치·목록 핸들러. "pkg" 프리픽스로 사용합니다.
///
/// 예: pkg                  → 사용법 안내
///     pkg vscode           → winget search vscode
///     pkg install {id}     → winget install {id}
///     pkg list             → 설치된 앱 목록
///     pkg upgrade          → 업그레이드 가능 목록
/// winget 미설치 시 안내 메시지 표시.
/// </summary>
public partial class PkgHandler : IActionHandler
{
    public string? Prefix => "pkg";

    public PluginMetadata Metadata => new(
        "앱 패키지",
        "winget 앱 검색·설치·업그레이드",
        "1.0",
        "AX");

    private static bool? _wingetAvailable;

    public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q     = query.Trim();
        var items = new List<LauncherItem>();

        // winget 설치 여부 체크 (캐시)
        _wingetAvailable ??= await CheckWingetAsync();
        if (_wingetAvailable == false)
        {
            items.Add(new LauncherItem(
                "winget이 설치되어 있지 않습니다",
                "Windows Package Manager는 Windows 10 1709+ 에서 사용 가능합니다",
                null, null, Symbol: Symbols.Warning));
            return items;
        }

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("winget 앱 패키지 관리",
                "pkg {검색어} · pkg install {id} · pkg list · pkg upgrade",
                null, null, Symbol: "\uECAA"));
            return items;
        }

        // ── list 명령 ─────────────────────────────────────────────────────────
        if (q.Equals("list", StringComparison.OrdinalIgnoreCase))
        {
            items.Add(new LauncherItem("설치된 앱 목록 조회 중...",
                "winget list 실행", null, ("list", ""), Symbol: "\uECAA"));
            // 실행 시 터미널에서 보여주기
            return items;
        }

        // ── upgrade 명령 ──────────────────────────────────────────────────────
        if (q.Equals("upgrade", StringComparison.OrdinalIgnoreCase))
        {
            items.Add(new LauncherItem("업그레이드 가능 앱 확인",
                "Enter: winget upgrade 실행", null, ("upgrade", ""), Symbol: "\uE777"));
            return items;
        }

        // ── install 명령 ──────────────────────────────────────────────────────
        if (q.StartsWith("install ", StringComparison.OrdinalIgnoreCase))
        {
            var id = q[8..].Trim();
            if (!string.IsNullOrWhiteSpace(id))
            {
                items.Add(new LauncherItem(
                    $"앱 설치: {id}",
                    $"Enter: winget install --id {id}",
                    null, ("install", id), Symbol: "\uE896"));
            }
            else
            {
                items.Add(new LauncherItem("사용법: pkg install {앱ID}",
                    "예: pkg install Microsoft.VisualStudioCode",
                    null, null, Symbol: Symbols.Info));
            }
            return items;
        }

        // ── 검색 ──────────────────────────────────────────────────────────────
        try
        {
            var results = await SearchAsync(q, ct);
            if (results.Count == 0)
            {
                items.Add(new LauncherItem($"'{q}' 검색 결과 없음",
                    "다른 검색어를 시도하세요", null, null, Symbol: Symbols.Search));
            }
            else
            {
                items.Add(new LauncherItem($"검색 결과: {results.Count}개",
                    "Enter: winget install --id {ID}", null, null, Symbol: Symbols.Search));

                foreach (var r in results.Take(10))
                {
                    items.Add(new LauncherItem(
                        $"{r.Name}  [{r.Version}]",
                        $"{r.Id}  ·  {r.Source}",
                        null, ("install", r.Id), Symbol: "\uECAA"));
                }
            }
        }
        catch (OperationCanceledException) { }
        catch (Exception ex)
        {
            items.Add(new LauncherItem("검색 오류", ex.Message, null, null, Symbol: Symbols.Error));
        }

        return items;
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("install", string id) && !string.IsNullOrWhiteSpace(id))
        {
            RunWingetInTerminal($"install --id \"{id}\" --accept-source-agreements --accept-package-agreements");
            NotificationService.Notify("pkg", $"설치 시작: {id}");
        }
        else if (item.Data is ("list", _))
        {
            RunWingetInTerminal("list");
        }
        else if (item.Data is ("upgrade", _))
        {
            RunWingetInTerminal("upgrade --include-unknown");
        }
        return Task.CompletedTask;
    }

    // ─── winget 검색 ──────────────────────────────────────────────────────────

    private record PkgResult(string Name, string Id, string Version, string Source);

    private static async Task<List<PkgResult>> SearchAsync(string query, CancellationToken ct)
    {
        var output = await RunWingetAsync($"search \"{query}\" --accept-source-agreements", ct);
        return ParseWingetOutput(output);
    }

    [GeneratedRegex(@"^(.+?)\s{2,}(\S+)\s{2,}(\S+)\s{2,}(\S+)\s*$")]
    private static partial Regex WingetLineRegex();

    private static List<PkgResult> ParseWingetOutput(string output)
    {
        var results = new List<PkgResult>();
        var lines = output.Split('\n');
        bool pastHeader = false;

        foreach (var rawLine in lines)
        {
            var line = rawLine.TrimEnd();

            // 헤더 구분선 (---) 이후부터 데이터
            if (line.StartsWith("---") || line.StartsWith("───"))
            {
                pastHeader = true;
                continue;
            }

            if (!pastHeader || string.IsNullOrWhiteSpace(line)) continue;

            var match = WingetLineRegex().Match(line);
            if (match.Success)
            {
                results.Add(new PkgResult(
                    match.Groups[1].Value.Trim(),
                    match.Groups[2].Value.Trim(),
                    match.Groups[3].Value.Trim(),
                    match.Groups[4].Value.Trim()));
            }
        }

        return results;
    }

    // ─── winget 실행 ──────────────────────────────────────────────────────────

    private static async Task<bool> CheckWingetAsync()
    {
        try
        {
            var output = await RunWingetAsync("--version", CancellationToken.None);
            return output.TrimStart().StartsWith('v');
        }
        catch { return false; }
    }

    private static async Task<string> RunWingetAsync(string args, CancellationToken ct)
    {
        using var proc = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "winget",
                Arguments = args,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = System.Text.Encoding.UTF8
            }
        };
        proc.Start();
        var output = await proc.StandardOutput.ReadToEndAsync(ct);
        await proc.WaitForExitAsync(ct);
        return output;
    }

    private static void RunWingetInTerminal(string args)
    {
        try
        {
            // 사용자에게 진행 상황이 보이도록 터미널 창으로 실행
            Process.Start(new ProcessStartInfo
            {
                FileName = "cmd.exe",
                Arguments = $"/k winget {args}",
                UseShellExecute = true
            });
        }
        catch (Exception ex)
        {
            LogService.Warn($"winget 실행 실패: {ex.Message}");
        }
    }
}
