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

namespace AxCopilot.Handlers;

/// <summary>
/// 텍스트 일괄 처리 핸들러. "batch" 프리픽스로 사용합니다.
/// 클립보드 텍스트의 각 줄에 동시에 변환을 적용합니다.
/// 예: batch prefix [텍스트]  → 각 줄 앞에 [텍스트] 추가
///     batch suffix [텍스트]  → 각 줄 뒤에 [텍스트] 추가
///     batch number           → 줄번호 추가
///     batch sort             → 줄 정렬
///     batch unique           → 중복 줄 제거
///     batch wrap "           → 각 줄을 "로 감싸기
///     batch replace A B      → A를 B로 치환
///     batch csv              → 줄 → CSV 한 줄로 합치기
///     batch split ,          → CSV 한 줄 → 여러 줄로 분리
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class BatchTextHandler : IActionHandler
{
    public string? Prefix => "batch";

    public PluginMetadata Metadata => new(
        "BatchText",
        "텍스트 일괄 처리 — batch",
        "1.0",
        "AX");

    private static readonly (string Cmd, string Desc)[] Commands =
    [
        ("prefix [텍스트]",  "각 줄 앞에 텍스트 추가"),
        ("suffix [텍스트]",  "각 줄 뒤에 텍스트 추가"),
        ("wrap [문자]",      "각 줄을 지정 문자로 감싸기 (예: wrap \")"),
        ("number",           "줄번호 추가 (1. 2. 3. ...)"),
        ("sort",             "줄 오름차순 정렬"),
        ("sortd",            "줄 내림차순 정렬"),
        ("reverse",          "줄 순서 뒤집기"),
        ("unique",           "중복 줄 제거"),
        ("trim",             "각 줄 앞뒤 공백 제거"),
        ("replace [A] [B]",  "A를 B로 전체 치환"),
        ("csv",              "줄들을 쉼표로 합쳐 한 줄로"),
        ("split [구분자]",   "한 줄을 구분자로 분리하여 여러 줄로"),
        ("indent [N]",       "각 줄 앞에 공백 N개 추가"),
        ("unindent",         "각 줄의 선행 공백/탭 제거"),
    ];

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

        if (string.IsNullOrWhiteSpace(q))
        {
            var items = Commands.Select(c => new LauncherItem(
                $"batch {c.Cmd}",
                c.Desc,
                null, null,
                Symbol: Symbols.Text)).ToList<LauncherItem>();

            items.Insert(0, new LauncherItem(
                "텍스트 일괄 처리",
                "클립보드 텍스트의 각 줄에 변환 적용  ·  명령 입력",
                null, null, Symbol: Symbols.Info));

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

        // 클립보드 읽기
        string? text = null;
        try
        {
            if (Application.Current?.Dispatcher.Invoke(() => Clipboard.ContainsText()) == true)
                text = Application.Current.Dispatcher.Invoke(() => Clipboard.GetText());
        }
        catch (Exception) { }

        if (string.IsNullOrEmpty(text))
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem("클립보드에 텍스트가 없습니다", "텍스트를 복사한 후 시도하세요",
                    null, null, Symbol: Symbols.Warning)
            ]);
        }

        var lines = text.Split('\n').Select(l => l.TrimEnd('\r')).ToArray();
        var parts = q.Split(' ', 2, StringSplitOptions.TrimEntries);
        var cmd = parts[0].ToLowerInvariant();
        var arg = parts.Length > 1 ? parts[1] : "";

        string? result = null;
        string? desc = null;

        try
        {
            switch (cmd)
            {
                case "prefix":
                    result = string.Join("\n", lines.Select(l => arg + l));
                    desc = $"각 줄 앞에 '{arg}' 추가";
                    break;
                case "suffix":
                    result = string.Join("\n", lines.Select(l => l + arg));
                    desc = $"각 줄 뒤에 '{arg}' 추가";
                    break;
                case "wrap":
                    var w = string.IsNullOrEmpty(arg) ? "\"" : arg;
                    result = string.Join("\n", lines.Select(l => w + l + w));
                    desc = $"각 줄을 '{w}'로 감싸기";
                    break;
                case "number":
                    result = string.Join("\n", lines.Select((l, i) => $"{i + 1}. {l}"));
                    desc = "줄번호 추가";
                    break;
                case "sort":
                    result = string.Join("\n", lines.Order());
                    desc = "오름차순 정렬";
                    break;
                case "sortd":
                    result = string.Join("\n", lines.OrderDescending());
                    desc = "내림차순 정렬";
                    break;
                case "reverse":
                    result = string.Join("\n", lines.Reverse());
                    desc = "줄 순서 뒤집기";
                    break;
                case "unique":
                    var unique = lines.Distinct().ToArray();
                    result = string.Join("\n", unique);
                    desc = $"중복 제거: {lines.Length}줄 → {unique.Length}줄";
                    break;
                case "trim":
                    result = string.Join("\n", lines.Select(l => l.Trim()));
                    desc = "각 줄 공백 제거";
                    break;
                case "replace":
                    var rParts = arg.Split(' ', 2, StringSplitOptions.TrimEntries);
                    if (rParts.Length == 2)
                    {
                        result = text.Replace(rParts[0], rParts[1]);
                        desc = $"'{rParts[0]}' → '{rParts[1]}' 치환";
                    }
                    break;
                case "csv":
                    result = string.Join(",", lines.Select(l => l.Trim()));
                    desc = $"{lines.Length}줄 → CSV 한 줄";
                    break;
                case "split":
                    var sep = string.IsNullOrEmpty(arg) ? "," : arg;
                    result = string.Join("\n", text.Split(sep));
                    desc = $"'{sep}' 기준 분리";
                    break;
                case "indent":
                    var n = int.TryParse(arg, out var indent) ? indent : 4;
                    var pad = new string(' ', n);
                    result = string.Join("\n", lines.Select(l => pad + l));
                    desc = $"{n}칸 들여쓰기";
                    break;
                case "unindent":
                    result = string.Join("\n", lines.Select(l => l.TrimStart(' ', '\t')));
                    desc = "선행 공백 제거";
                    break;
            }
        }
        catch (Exception ex)
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem($"처리 오류: {ex.Message}", "입력 데이터를 확인하세요",
                    null, null, Symbol: Symbols.Error)
            ]);
        }

        if (result == null)
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem($"알 수 없는 명령: {cmd}", "batch 만 입력하면 전체 명령 목록",
                    null, null, Symbol: Symbols.Warning)
            ]);
        }

        var preview = result.Length > 120 ? result[..117] + "…" : result;
        preview = preview.Replace("\n", "↵ ");

        return Task.FromResult<IEnumerable<LauncherItem>>(
        [
            new LauncherItem(
                $"[{desc}] → Enter로 클립보드 복사",
                preview,
                null, result,
                Symbol: Symbols.Text)
        ]);
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is string text)
        {
            try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(text)); }
            catch (Exception) { }
            NotificationService.Notify("일괄 처리 완료", "변환 결과가 클립보드에 복사되었습니다");
        }
        return Task.CompletedTask;
    }
}
