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

namespace AxCopilot.Handlers;

/// <summary>
/// L18-2: 텍스트 케이스 변환 핸들러. "text" 프리픽스로 사용합니다.
///
/// 예: text                   → 클립보드 텍스트 모든 케이스 변환 목록
///     text camel             → camelCase
///     text pascal            → PascalCase
///     text snake             → snake_case
///     text kebab             → kebab-case
///     text slug              → url-slug (소문자 + 하이픈)
///     text upper             → UPPER CASE
///     text lower             → lower case
///     text title             → Title Case
///     text sentence          → Sentence case
///     text const             → SCREAMING_SNAKE_CASE
///     text dot               → dot.case
///     text reverse           → 문자 순서 뒤집기
///     text trim              → 앞뒤 공백·줄바꿈 제거
/// Enter → 결과 복사.
/// </summary>
public partial class TextCaseHandler : IActionHandler
{
    public string? Prefix => "text";

    public PluginMetadata Metadata => new(
        "Text",
        "텍스트 케이스 변환 — camelCase · snake_case · PascalCase · slug 등",
        "1.0",
        "AX");

    private record CaseItem(string Name, string Key, Func<string, string> Convert);

    private static readonly CaseItem[] Cases =
    [
        new("camelCase",               "camel",    ToCamel),
        new("PascalCase",              "pascal",   ToPascal),
        new("snake_case",              "snake",    ToSnake),
        new("SCREAMING_SNAKE_CASE",    "const",    ToConst),
        new("kebab-case",              "kebab",    ToKebab),
        new("URL slug",                "slug",     ToSlug),
        new("dot.case",                "dot",      ToDot),
        new("UPPER CASE",              "upper",    s => s.ToUpperInvariant()),
        new("lower case",              "lower",    s => s.ToLowerInvariant()),
        new("Title Case",              "title",    ToTitle),
        new("Sentence case",           "sentence", ToSentence),
        new("뒤집기 (reverse)",        "reverse",  s => new string(s.Reverse().ToArray())),
        new("공백 정리 (trim)",        "trim",     s => s.Trim()),
    ];

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

        string? clipboard = null;
        try
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                if (Clipboard.ContainsText())
                    clipboard = Clipboard.GetText().Trim();
            });
        }
        catch { }

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("텍스트 케이스 변환기",
                "클립보드 텍스트를 다양한 케이스로 변환  ·  text camel / snake / pascal / kebab…",
                null, null, Symbol: "\uE8AB"));

            if (string.IsNullOrWhiteSpace(clipboard))
            {
                items.Add(new LauncherItem("클립보드가 비어 있습니다",
                    "텍스트를 복사한 뒤 사용하세요", null, null, Symbol: "\uE946"));
                // 케이스 목록만 안내
                foreach (var c in Cases)
                    items.Add(new LauncherItem($"text {c.Key}", c.Name, null, null, Symbol: "\uE8AB"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }

            // 클립보드 텍스트 → 모든 케이스 변환 목록
            var preview = clipboard.Length > 30 ? clipboard[..30] + "…" : clipboard;
            items.Add(new LauncherItem($"입력: \"{preview}\"", $"{clipboard.Length}자  · 아래에서 선택",
                null, null, Symbol: "\uE8AB"));

            foreach (var c in Cases)
            {
                var result = TrySafeConvert(c.Convert, clipboard);
                items.Add(new LauncherItem(result, c.Name,
                    null, ("copy", result), Symbol: "\uE8AB"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 서브커맨드로 특정 케이스 변환
        var parts  = q.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
        var sub    = parts[0].ToLowerInvariant();
        // 인라인 텍스트 입력 지원: text camel hello world → helloWorld
        var inlineText = parts.Length > 1 ? parts[1] : clipboard;

        if (string.IsNullOrWhiteSpace(inlineText))
        {
            items.Add(new LauncherItem("텍스트가 없습니다",
                "클립보드에 텍스트를 복사하거나 text camel <직접입력> 형식으로 사용하세요",
                null, null, Symbol: "\uE946"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var caseItem = Cases.FirstOrDefault(c =>
            c.Key.Equals(sub, StringComparison.OrdinalIgnoreCase));

        if (caseItem != null)
        {
            var result = TrySafeConvert(caseItem.Convert, inlineText);
            var sourceLabel = parts.Length > 1 ? $"입력: \"{inlineText}\"" : $"클립보드: \"{(inlineText.Length > 30 ? inlineText[..30] + "…" : inlineText)}\"";
            items.Add(new LauncherItem(result,
                $"{caseItem.Name}  · Enter 복사", null, ("copy", result), Symbol: "\uE8AB"));
            items.Add(new LauncherItem(sourceLabel, "원본", null, ("copy", inlineText), Symbol: "\uE8AB"));

            // 다른 케이스도 함께 표시
            items.Add(new LauncherItem("── 다른 케이스 ──", "", null, null, Symbol: "\uE8AB"));
            foreach (var c in Cases.Where(c => c.Key != sub))
            {
                var r = TrySafeConvert(c.Convert, inlineText);
                if (r != result)
                    items.Add(new LauncherItem(r, c.Name, null, ("copy", r), Symbol: "\uE8AB"));
            }
        }
        else
        {
            // 알 수 없는 서브커맨드 → 모든 케이스 변환
            items.Add(new LauncherItem($"알 수 없는 케이스: '{sub}'",
                "camel · pascal · snake · const · kebab · slug · dot · upper · lower · title · sentence · reverse · trim",
                null, null, Symbol: "\uE783"));

            if (!string.IsNullOrWhiteSpace(clipboard))
            {
                foreach (var c in Cases)
                {
                    var r = TrySafeConvert(c.Convert, clipboard);
                    items.Add(new LauncherItem(r, c.Name, null, ("copy", r), Symbol: "\uE8AB"));
                }
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("copy", string text))
        {
            try
            {
                System.Windows.Application.Current.Dispatcher.Invoke(
                    () => Clipboard.SetText(text));
                NotificationService.Notify("Text", "클립보드에 복사했습니다.");
            }
            catch { }
        }
        return Task.CompletedTask;
    }

    // ── 변환 함수 ─────────────────────────────────────────────────────────────

    private static string TrySafeConvert(Func<string, string> fn, string input)
    {
        try { return fn(input); }
        catch { return input; }
    }

    /// <summary>입력을 단어 토큰 배열로 분리 (공백, 언더스코어, 하이픈, 대문자 경계)</summary>
    private static string[] Tokenize(string s)
    {
        // camelCase/PascalCase 분리
        var withSpaces = CamelBoundaryRegex().Replace(s, "$1 $2");
        // 구분자 → 공백
        var normalized = SeparatorRegex().Replace(withSpaces, " ");
        return normalized.Split(' ', StringSplitOptions.RemoveEmptyEntries);
    }

    private static string ToCamel(string s)
    {
        var words = Tokenize(s);
        if (words.Length == 0) return s;
        var sb = new StringBuilder(words[0].ToLowerInvariant());
        for (var i = 1; i < words.Length; i++)
            sb.Append(char.ToUpperInvariant(words[i][0]) + words[i][1..].ToLowerInvariant());
        return sb.ToString();
    }

    private static string ToPascal(string s)
    {
        var words = Tokenize(s);
        var sb    = new StringBuilder();
        foreach (var w in words)
            sb.Append(char.ToUpperInvariant(w[0]) + w[1..].ToLowerInvariant());
        return sb.ToString();
    }

    private static string ToSnake(string s) =>
        string.Join("_", Tokenize(s).Select(w => w.ToLowerInvariant()));

    private static string ToConst(string s) =>
        string.Join("_", Tokenize(s).Select(w => w.ToUpperInvariant()));

    private static string ToKebab(string s) =>
        string.Join("-", Tokenize(s).Select(w => w.ToLowerInvariant()));

    private static string ToSlug(string s)
    {
        var normalized = s.Normalize(NormalizationForm.FormD);
        var ascii      = new StringBuilder();
        foreach (var c in normalized)
            if (c < 128) ascii.Append(c);
        var slug = SeparatorRegex().Replace(ascii.ToString().ToLowerInvariant(), "-");
        slug = NonSlugRegex().Replace(slug, "");
        slug = MultipleDashRegex().Replace(slug, "-");
        return slug.Trim('-');
    }

    private static string ToDot(string s) =>
        string.Join(".", Tokenize(s).Select(w => w.ToLowerInvariant()));

    private static string ToTitle(string s)
    {
        var words = s.Split(' ');
        return string.Join(" ", words.Select(w =>
            w.Length == 0 ? w : char.ToUpperInvariant(w[0]) + w[1..].ToLowerInvariant()));
    }

    private static string ToSentence(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        var lower = s.ToLowerInvariant();
        return char.ToUpperInvariant(lower[0]) + lower[1..];
    }

    [GeneratedRegex(@"([a-z])([A-Z])")]
    private static partial Regex CamelBoundaryRegex();

    [GeneratedRegex(@"[\s\-_./\\]+")]
    private static partial Regex SeparatorRegex();

    [GeneratedRegex(@"[^a-z0-9\-]")]
    private static partial Regex NonSlugRegex();

    [GeneratedRegex(@"-{2,}")]
    private static partial Regex MultipleDashRegex();
}
