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

namespace AxCopilot.Handlers;

/// <summary>
/// L7-1: Git 빠른 조회 핸들러. "git" 프리픽스로 사용합니다.
///
/// 예: git                → 최근 작업 폴더(또는 현재 앱 폴더)의 git 상태 요약
///     git status         → git status --short 출력
///     git log            → 최근 커밋 10개
///     git branch         → 브랜치 목록 (현재 브랜치 강조)
///     git stash          → stash 목록
///     git diff           → git diff --stat 요약
///     git pull           → git pull 실행
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class GitHandler : IActionHandler
{
    public string? Prefix => "git";

    public PluginMetadata Metadata => new(
        "Git",
        "Git 빠른 조회 — git status · log · branch · stash",
        "1.0",
        "AX");

    // ── 서브커맨드 정의 ──────────────────────────────────────────────────────
    private static readonly (string Sub, string Args, string Label, string Icon)[] SubCommands =
    [
        ("status",  "status --short",        "변경 파일 목록",     "\uE9F5"),
        ("log",     "log --oneline -10",     "최근 커밋 10개",     "\uE81C"),
        ("branch",  "branch -a",             "브랜치 목록",        "\uE8FB"),
        ("stash",   "stash list",            "Stash 목록",         "\uE7C4"),
        ("diff",    "diff --stat",           "변경 통계",          "\uE8A1"),
        ("pull",    "pull",                  "git pull 실행",      "\uE8AF"),
    ];

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

        // 작업 디렉토리 결정
        var workDir = FindGitRoot();

        if (string.IsNullOrEmpty(q))
        {
            // 빠른 상태 요약
            if (!string.IsNullOrEmpty(workDir))
            {
                var branch = await RunGitAsync("branch --show-current", workDir, ct);
                var statusOut = await RunGitAsync("status --short", workDir, ct);
                var changed = statusOut?.Split('\n', StringSplitOptions.RemoveEmptyEntries).Length ?? 0;

                items.Add(new LauncherItem(
                    $"Git: {branch?.Trim() ?? "unknown"}",
                    changed == 0 ? "변경 없음" : $"{changed}개 파일 변경됨 · {System.IO.Path.GetFileName(workDir)}",
                    null,
                    ("status_summary", workDir),
                    Symbol: "\uE9F5"));
            }
            else
            {
                items.Add(new LauncherItem("Git 저장소 없음",
                    "현재 작업 폴더에 .git 디렉토리가 없습니다", null, null,
                    Symbol: "\uE783"));
            }

            // 서브커맨드 목록
            foreach (var (sub, args, label, icon) in SubCommands)
            {
                items.Add(new LauncherItem(
                    $"git {sub}",
                    label,
                    null,
                    (sub, workDir ?? ""),
                    Symbol: icon));
            }
            return items;
        }

        // 서브커맨드 매칭
        var matched = SubCommands
            .Where(sc => sc.Sub.StartsWith(q, StringComparison.OrdinalIgnoreCase))
            .ToList();

        if (matched.Count > 0)
        {
            foreach (var (sub, args, label, icon) in matched)
            {
                string? preview = null;
                if (!string.IsNullOrEmpty(workDir))
                    preview = await RunGitAsync(args, workDir, ct);

                var subtitle = preview != null
                    ? TruncateLines(preview, 3)
                    : label;

                items.Add(new LauncherItem(
                    $"git {sub}",
                    subtitle,
                    null,
                    (sub, workDir ?? "", args),
                    Symbol: icon));
            }
        }
        else
        {
            // 자유 명령 실행 (git <query>)
            string? output = null;
            if (!string.IsNullOrEmpty(workDir))
                output = await RunGitAsync(q, workDir, ct);

            items.Add(new LauncherItem(
                $"git {query.Trim()}",
                output != null ? TruncateLines(output, 3) : "실행 후 결과 클립보드 복사",
                null,
                ("custom", workDir ?? "", query.Trim()),
                Symbol: "\uE9F5"));
        }

        return items;
    }

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        string? result = null;

        switch (item.Data)
        {
            // 상태 요약 항목
            case ("status_summary", string workDir):
                result = await RunGitAsync("status", workDir, ct);
                break;

            // 서브커맨드 항목 (sub, workDir, args)
            case (string sub, string workDir, string args):
                if (sub == "pull")
                {
                    // pull은 별도 터미널 창으로 실행
                    if (!string.IsNullOrEmpty(workDir))
                    {
                        Process.Start(new ProcessStartInfo
                        {
                            FileName = "powershell.exe",
                            Arguments = $"-NoProfile -Command \"cd '{workDir}'; git pull; Read-Host 'Enter 키를 누르면 닫힙니다'\"",
                            UseShellExecute = true,
                        });
                    }
                    return;
                }
                result = await RunGitAsync(args, workDir, ct);
                break;

            // 서브커맨드 항목 (sub, workDir) — args 없는 경우
            case (string sub2, string workDir2):
                var found = SubCommands.FirstOrDefault(sc => sc.Sub == sub2);
                if (found != default)
                    result = await RunGitAsync(found.Args, workDir2, ct);
                break;

            default:
                break;
        }

        if (!string.IsNullOrWhiteSpace(result))
        {
            try
            {
                System.Windows.Application.Current.Dispatcher.Invoke(
                    () => Clipboard.SetText(result));
                NotificationService.Notify("Git", "결과를 클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
        }
    }

    // ── 헬퍼 ────────────────────────────────────────────────────────────────

    /// <summary>현재 앱 설정의 작업 폴더에서 .git root를 찾습니다.</summary>
    private static string? FindGitRoot()
    {
        var app = System.Windows.Application.Current as App;
        var workDir = app?.SettingsService?.Settings.Llm.WorkFolder ?? "";

        if (string.IsNullOrEmpty(workDir) || !System.IO.Directory.Exists(workDir))
            workDir = AppDomain.CurrentDomain.BaseDirectory;

        // .git 폴더를 찾아 상위로 이동
        var dir = new System.IO.DirectoryInfo(workDir);
        while (dir != null)
        {
            if (System.IO.Directory.Exists(System.IO.Path.Combine(dir.FullName, ".git")))
                return dir.FullName;
            dir = dir.Parent;
        }
        return null;
    }

    /// <summary>git 명령을 비동기로 실행하고 출력을 반환합니다.</summary>
    private static async Task<string?> RunGitAsync(string args, string workDir, CancellationToken ct)
    {
        if (string.IsNullOrEmpty(workDir)) return null;
        try
        {
            var psi = new ProcessStartInfo("git", args)
            {
                WorkingDirectory      = workDir,
                UseShellExecute       = false,
                RedirectStandardOutput = true,
                RedirectStandardError  = true,
                CreateNoWindow        = true,
                StandardOutputEncoding = Encoding.UTF8,
            };

            using var proc = Process.Start(psi);
            if (proc == null) return null;

            var output = await proc.StandardOutput.ReadToEndAsync(ct);
            var error  = await proc.StandardError.ReadToEndAsync(ct);
            await proc.WaitForExitAsync(ct);

            var text = output.Trim();
            if (string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(error))
                text = error.Trim();

            return string.IsNullOrWhiteSpace(text) ? "(출력 없음)" : text;
        }
        catch (OperationCanceledException)
        {
            return null;
        }
        catch (Exception ex)
        {
            return $"오류: {ex.Message}";
        }
    }

    /// <summary>긴 출력을 maxLines줄로 자릅니다.</summary>
    private static string TruncateLines(string text, int maxLines)
    {
        var lines = text.Split('\n', StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length <= maxLines) return string.Join(" · ", lines.Take(maxLines)).Trim();
        return string.Join(" · ", lines.Take(maxLines)) + $" … (+{lines.Length - maxLines}줄)";
    }
}
