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

namespace AxCopilot.Handlers;

/// <summary>
/// L7-2: 정규식 테스터 핸들러. "re" 프리픽스로 사용합니다.
///
/// 예: re \d+              → 클립보드 텍스트에서 숫자 패턴 매치
///     re /old/new/        → 치환 모드 (결과 클립보드 복사)
///     re patterns         → 공통 패턴 라이브러리 표시
///     re flags:i \w+      → 플래그 지정 (i=무시대소, m=멀티라인, s=점이개행)
/// Enter → 매치 결과 또는 치환 결과를 클립보드에 복사.
/// </summary>
public class RegexHandler : IActionHandler
{
    public string? Prefix => "re";

    public PluginMetadata Metadata => new(
        "Regex",
        "정규식 테스터 — 매치 · 치환 · 패턴 라이브러리",
        "1.0",
        "AX");

    // ── 공통 패턴 라이브러리 ─────────────────────────────────────────────────
    private static readonly (string Name, string Pattern, string Desc)[] CommonPatterns =
    [
        ("이메일",       @"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}",  "이메일 주소"),
        ("URL",          @"https?://[^\s/$.?#].[^\s]*",                           "HTTP/HTTPS URL"),
        ("전화번호",     @"0\d{1,2}-\d{3,4}-\d{4}",                              "한국 전화번호 (하이픈)"),
        ("날짜",         @"\d{4}[-./]\d{1,2}[-./]\d{1,2}",                       "날짜 (YYYY-MM-DD 등)"),
        ("숫자",         @"\d+(?:\.\d+)?",                                        "정수 또는 소수"),
        ("한글",         @"[가-힣]+",                                              "한글 문자열"),
        ("영문",         @"[a-zA-Z]+",                                            "영문 문자열"),
        ("IP 주소",      @"\b(?:\d{1,3}\.){3}\d{1,3}\b",                         "IPv4 주소"),
        ("16진수 색상",  @"#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b",               "HEX 색상 코드"),
        ("빈 줄",        @"^\s*$",                                                 "빈 줄 (멀티라인 모드 필요)"),
        ("HTML 태그",    @"<[^>]+>",                                              "HTML 태그"),
        ("JSON 키",      @"""([^""]+)""\s*:",                                     "JSON 키 이름"),
        ("UUID",         @"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", "UUID"),
        ("우편번호",     @"\b\d{5}\b",                                             "5자리 우편번호"),
    ];

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

        if (string.IsNullOrWhiteSpace(q))
        {
            // 안내 + 패턴 라이브러리 미리보기
            items.Add(new LauncherItem(
                "정규식 테스터",
                "패턴 입력 후 Enter → 클립보드 텍스트에서 매치. /old/new/ 형식으로 치환",
                null, null, Symbol: "\uE773"));

            items.Add(new LauncherItem(
                "re patterns",
                "공통 패턴 라이브러리 표시",
                null, ("show_patterns", ""), Symbol: "\uE8A4"));

            foreach (var (name, pattern, desc) in CommonPatterns.Take(5))
            {
                items.Add(new LauncherItem(
                    name,
                    $"{pattern}  ·  {desc}",
                    null,
                    ("pattern_apply", pattern),
                    Symbol: "\uE773"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // "patterns" 서브커맨드
        if (q.Equals("patterns", StringComparison.OrdinalIgnoreCase))
        {
            foreach (var (name, pattern, desc) in CommonPatterns)
            {
                items.Add(new LauncherItem(
                    name,
                    $"{pattern}  ·  {desc}",
                    null,
                    ("pattern_apply", pattern),
                    Symbol: "\uE773"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 공통 패턴 이름 검색
        var matchedPatterns = CommonPatterns
            .Where(p => p.Name.Contains(q, StringComparison.OrdinalIgnoreCase) ||
                        p.Desc.Contains(q, StringComparison.OrdinalIgnoreCase))
            .ToList();
        if (matchedPatterns.Count > 0)
        {
            foreach (var (name, pattern, desc) in matchedPatterns)
            {
                items.Add(new LauncherItem(
                    name,
                    $"{pattern}  ·  {desc}",
                    null,
                    ("pattern_apply", pattern),
                    Symbol: "\uE773"));
            }
        }

        // 치환 모드 /old/new/
        if (q.StartsWith('/') && q.Length > 2)
        {
            var parts = q.Split('/', StringSplitOptions.None);
            // /old/new/ → parts = ["", "old", "new", ""]
            if (parts.Length >= 3)
            {
                var oldPat = parts[1];
                var newStr = parts.Length >= 3 ? parts[2] : "";
                var flags  = parts.Length >= 4 ? parts[3] : "";

                var clipText = GetClipboardText();
                if (!string.IsNullOrEmpty(clipText) && !string.IsNullOrEmpty(oldPat))
                {
                    try
                    {
                        var opts = BuildOptions(flags);
                        var result = Regex.Replace(clipText, oldPat, newStr, opts);
                        var changed = result != clipText;
                        items.Add(new LauncherItem(
                            changed ? "치환 완료 — 클립보드 복사" : "치환 없음 (패턴 불일치)",
                            result.Length > 120 ? result[..120] + "…" : result,
                            null,
                            ("replace_result", result),
                            Symbol: "\uE8AC"));
                    }
                    catch (Exception ex)
                    {
                        items.Add(new LauncherItem("패턴 오류", ex.Message, null, null, Symbol: "\uE783"));
                    }
                }
                else
                {
                    items.Add(new LauncherItem(
                        $"치환: /{oldPat}/ → {newStr}",
                        "클립보드에 텍스트를 복사한 뒤 실행하세요",
                        null, ("replace_pattern", oldPat, newStr), Symbol: "\uE8AC"));
                }
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
        }

        // 플래그 처리: "flags:im pattern"
        string pattern2 = q;
        string flagStr = "";
        if (q.StartsWith("flags:", StringComparison.OrdinalIgnoreCase))
        {
            var spaceIdx = q.IndexOf(' ');
            if (spaceIdx > 0)
            {
                flagStr   = q[6..spaceIdx];
                pattern2  = q[(spaceIdx + 1)..].Trim();
            }
        }

        // 매치 모드
        if (!string.IsNullOrEmpty(pattern2))
        {
            var clipText = GetClipboardText();
            if (!string.IsNullOrEmpty(clipText))
            {
                try
                {
                    var opts    = BuildOptions(flagStr);
                    var matches = Regex.Matches(clipText, pattern2, opts);

                    if (matches.Count == 0)
                    {
                        items.Add(new LauncherItem(
                            "매치 없음",
                            $"패턴 [{pattern2}]이 클립보드 텍스트와 일치하지 않습니다",
                            null, null, Symbol: "\uE783"));
                    }
                    else
                    {
                        // 요약 항목
                        items.Add(new LauncherItem(
                            $"{matches.Count}개 매치됨",
                            $"패턴: {pattern2}  |  전체 복사: Enter",
                            null,
                            ("all_matches", string.Join("\n", matches.Cast<Match>().Select(m => m.Value))),
                            Symbol: "\uE773"));

                        // 개별 매치 항목 (최대 15개)
                        foreach (Match m in matches.Cast<Match>().Take(15))
                        {
                            var groupInfo = m.Groups.Count > 1
                                ? " · 그룹: " + string.Join(", ", m.Groups.Cast<Group>().Skip(1).Select(g => g.Value))
                                : "";
                            items.Add(new LauncherItem(
                                m.Value,
                                $"위치 {m.Index}{groupInfo}",
                                null,
                                ("single_match", m.Value),
                                Symbol: "\uE773"));
                        }

                        if (matches.Count > 15)
                            items.Add(new LauncherItem(
                                $"… +{matches.Count - 15}개 더",
                                "전체 보기: 첫 번째 항목 Enter",
                                null, null, Symbol: "\uE712"));
                    }
                }
                catch (Exception ex)
                {
                    items.Add(new LauncherItem("패턴 오류", ex.Message, null, null, Symbol: "\uE783"));
                }
            }
            else
            {
                // 클립보드 없음 → 패턴만 표시
                items.Add(new LauncherItem(
                    $"패턴: {pattern2}",
                    "클립보드에 텍스트를 복사한 뒤 실행하세요",
                    null,
                    ("pattern_apply", pattern2),
                    Symbol: "\uE773"));
            }
        }

        return Task.FromResult<IEnumerable<LauncherItem>>(items);
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("all_matches", string copyText1):
                TryCopyToClipboard(copyText1);
                break;
            case ("replace_result", string copyText2):
                TryCopyToClipboard(copyText2);
                break;
            case ("single_match", string copyText3):
                TryCopyToClipboard(copyText3);
                break;

            case ("pattern_apply", string pattern):
                // 패턴을 클립보드에 복사 (또는 클립보드 텍스트에 즉시 적용)
                var clipText = GetClipboardText();
                if (!string.IsNullOrEmpty(clipText))
                {
                    try
                    {
                        var matches = Regex.Matches(clipText, pattern);
                        if (matches.Count > 0)
                        {
                            var result = string.Join("\n", matches.Cast<Match>().Select(m => m.Value));
                            TryCopyToClipboard(result);
                            NotificationService.Notify("Regex", $"{matches.Count}개 매치 복사됨");
                        }
                        else
                        {
                            NotificationService.Notify("Regex", "매치 없음");
                        }
                    }
                    catch
                    {
                        TryCopyToClipboard(pattern);
                        NotificationService.Notify("Regex", "패턴을 클립보드에 복사했습니다");
                    }
                }
                else
                {
                    TryCopyToClipboard(pattern);
                    NotificationService.Notify("Regex", "패턴을 클립보드에 복사했습니다");
                }
                break;

            case ("replace_pattern", string oldPat, string newStr):
                var src = GetClipboardText();
                if (!string.IsNullOrEmpty(src))
                {
                    try
                    {
                        var replaced = Regex.Replace(src, oldPat, newStr);
                        TryCopyToClipboard(replaced);
                        NotificationService.Notify("Regex", "치환 결과를 클립보드에 복사했습니다");
                    }
                    catch (Exception ex)
                    {
                        NotificationService.Notify("Regex", $"오류: {ex.Message}");
                    }
                }
                break;

            case ("show_patterns", _):
                // 패턴 라이브러리 목록 표시 — 런처 입력창에 "re patterns" 입력
                var launcher = System.Windows.Application.Current?.Windows
                    .OfType<Views.LauncherWindow>()
                    .FirstOrDefault();
                launcher?.SetInputText("re patterns ");
                break;
        }
        return Task.CompletedTask;
    }

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

    private static RegexOptions BuildOptions(string flags)
    {
        var opts = RegexOptions.None;
        if (flags.Contains('i', StringComparison.OrdinalIgnoreCase)) opts |= RegexOptions.IgnoreCase;
        if (flags.Contains('m', StringComparison.OrdinalIgnoreCase)) opts |= RegexOptions.Multiline;
        if (flags.Contains('s', StringComparison.OrdinalIgnoreCase)) opts |= RegexOptions.Singleline;
        return opts;
    }

    private static string? GetClipboardText()
    {
        try
        {
            string? text = null;
            System.Windows.Application.Current.Dispatcher.Invoke(
                () => text = Clipboard.ContainsText() ? Clipboard.GetText() : null);
            return text;
        }
        catch { return null; }
    }

    private static void TryCopyToClipboard(string text)
    {
        try
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
        }
        catch { /* 비핵심 */ }
    }
}
