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

namespace AxCopilot.Handlers;

/// <summary>
/// L16-4: 텍스트 → 표 변환 핸들러. "table" 프리픽스로 사용합니다.
///
/// 클립보드 텍스트(탭 구분, CSV, 공백 정렬)를 표로 변환합니다.
///
/// 예: table                  → 클립보드 → 마크다운 표 변환
///     table csv              → 마크다운 → CSV 변환
///     table html             → 마크다운 → HTML 테이블 변환
///     table flip             → 행·열 전치(transpose)
///     table sort 2           → 2번 열 기준 정렬
///     table add <헤더>       → 새 행 추가 (탭 구분)
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class TableHandler : IActionHandler
{
    public string? Prefix => "table";

    public PluginMetadata Metadata => new(
        "Table",
        "텍스트·CSV → 마크다운·HTML 표 변환 — 전치 · 정렬 · 추가",
        "1.0",
        "AX");

    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();
            });
        }
        catch { /* 클립보드 접근 실패 */ }

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("텍스트 → 표 변환기",
                "클립보드 탭·CSV·공백 구분 텍스트를 표로 변환  ·  table csv / html / flip / sort N",
                null, null, Symbol: "\uE81E"));
            items.Add(new LauncherItem("table",       "→ 마크다운 표",            null, null, Symbol: "\uE81E"));
            items.Add(new LauncherItem("table csv",   "→ CSV 변환",              null, null, Symbol: "\uE81E"));
            items.Add(new LauncherItem("table html",  "→ HTML 테이블",           null, null, Symbol: "\uE81E"));
            items.Add(new LauncherItem("table flip",  "행·열 전치 (transpose)",  null, null, Symbol: "\uE81E"));
            items.Add(new LauncherItem("table sort 2","2열 기준 정렬",           null, null, Symbol: "\uE81E"));

            if (string.IsNullOrWhiteSpace(clipboard))
            {
                items.Add(new LauncherItem("클립보드가 비어 있습니다",
                    "탭·쉼표·공백 구분 표 데이터를 복사한 뒤 사용하세요",
                    null, null, Symbol: "\uE946"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }

            // 미리보기
            var previewRows = ParseTable(clipboard);
            if (previewRows.Count > 0)
            {
                var md = ToMarkdown(previewRows);
                items.Add(new LauncherItem($"마크다운 표 변환  ({previewRows.Count}행 × {previewRows[0].Count}열)",
                    "Enter → 변환 결과 복사", null, ("copy", md), Symbol: "\uE81E"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        if (string.IsNullOrWhiteSpace(clipboard))
        {
            items.Add(new LauncherItem("클립보드가 비어 있습니다",
                "표 데이터를 복사한 뒤 사용하세요", null, null, Symbol: "\uE946"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var parts  = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        var sub    = parts[0].ToLowerInvariant();
        var rows   = ParseTable(clipboard);

        if (rows.Count == 0)
        {
            items.Add(new LauncherItem("표로 변환할 수 없습니다",
                "탭·쉼표·공백 구분 데이터가 아닌 것 같습니다",
                null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        switch (sub)
        {
            case "csv":
            {
                var csv = ToCsv(rows);
                items.Add(new LauncherItem($"CSV 변환  ({rows.Count}행 × {rows[0].Count}열)",
                    "Enter → CSV 복사", null, ("copy", csv), Symbol: "\uE81E"));
                AddPreview(items, csv);
                break;
            }

            case "html":
            {
                var html = ToHtml(rows);
                items.Add(new LauncherItem($"HTML 테이블  ({rows.Count}행 × {rows[0].Count}열)",
                    "Enter → HTML 복사", null, ("copy", html), Symbol: "\uE81E"));
                AddPreview(items, html);
                break;
            }

            case "md":
            case "markdown":
            {
                var md = ToMarkdown(rows);
                items.Add(new LauncherItem($"마크다운 표  ({rows.Count}행 × {rows[0].Count}열)",
                    "Enter → 복사", null, ("copy", md), Symbol: "\uE81E"));
                AddPreview(items, md);
                break;
            }

            case "flip":
            case "transpose":
            {
                var flipped = Transpose(rows);
                var md      = ToMarkdown(flipped);
                items.Add(new LauncherItem($"전치됨  ({flipped.Count}행 × {flipped[0].Count}열)",
                    "Enter → 마크다운 복사", null, ("copy", md), Symbol: "\uE81E"));
                var csv = ToCsv(flipped);
                items.Add(new LauncherItem("CSV로 복사", $"{flipped.Count}행 × {flipped[0].Count}열",
                    null, ("copy", csv), Symbol: "\uE81E"));
                break;
            }

            case "sort":
            {
                var colIdx = parts.Length > 1 && int.TryParse(parts[1], out var ci) ? ci - 1 : 0;
                var sorted = SortByColumn(rows, colIdx);
                var md     = ToMarkdown(sorted);
                items.Add(new LauncherItem($"{colIdx + 1}열 기준 정렬",
                    "Enter → 마크다운 복사", null, ("copy", md), Symbol: "\uE81E"));
                AddPreview(items, md);
                break;
            }

            default:
            {
                // 기본: 마크다운 변환
                var md = ToMarkdown(rows);
                items.Add(new LauncherItem($"마크다운 표  ({rows.Count}행 × {rows[0].Count}열)",
                    "Enter → 복사", null, ("copy", md), Symbol: "\uE81E"));
                var csv = ToCsv(rows);
                items.Add(new LauncherItem("CSV로 복사", $"{rows.Count}행",
                    null, ("copy", csv), Symbol: "\uE81E"));
                var html = ToHtml(rows);
                items.Add(new LauncherItem("HTML로 복사", "테이블 태그",
                    null, ("copy", html), Symbol: "\uE81E"));
                break;
            }
        }

        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("Table", "클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
        }
        return Task.CompletedTask;
    }

    // ── 파서 ─────────────────────────────────────────────────────────────────

    /// <summary>탭, 쉼표(CSV), 연속 공백 순으로 자동 감지하여 표로 파싱</summary>
    private static List<List<string>> ParseTable(string text)
    {
        var lines = text.Split('\n')
            .Select(l => l.TrimEnd('\r'))
            .Where(l => !string.IsNullOrWhiteSpace(l))
            .ToList();

        if (lines.Count == 0) return new List<List<string>>();

        // 구분자 자동 감지
        var tabCount   = lines[0].Count(c => c == '\t');
        var commaCount = lines[0].Count(c => c == ',');

        char delimiter;
        if (tabCount > 0)        delimiter = '\t';
        else if (commaCount > 0) delimiter = ',';
        else                     delimiter = '\t'; // 공백 구분은 단순 분할

        var rows = new List<List<string>>();
        foreach (var line in lines)
        {
            var cols = delimiter == ','
                ? ParseCsvLine(line)
                : line.Split(delimiter).Select(c => c.Trim()).ToList();
            rows.Add(cols);
        }

        // 열 수 통일 (가장 많은 열 수 기준 패딩)
        var maxCols = rows.Max(r => r.Count);
        foreach (var row in rows)
            while (row.Count < maxCols) row.Add("");

        return rows;
    }

    private static List<string> ParseCsvLine(string line)
    {
        var result  = new List<string>();
        var current = new StringBuilder();
        var inQuote = false;

        for (var i = 0; i < line.Length; i++)
        {
            var c = line[i];
            if (c == '"')
            {
                if (inQuote && i + 1 < line.Length && line[i + 1] == '"') { current.Append('"'); i++; }
                else inQuote = !inQuote;
            }
            else if (c == ',' && !inQuote)
            {
                result.Add(current.ToString());
                current.Clear();
            }
            else current.Append(c);
        }
        result.Add(current.ToString());
        return result;
    }

    // ── 변환 ─────────────────────────────────────────────────────────────────

    private static string ToMarkdown(List<List<string>> rows)
    {
        if (rows.Count == 0) return "";
        var sb      = new StringBuilder();
        var maxCols = rows.Max(r => r.Count);

        // 각 열 최대 너비
        var widths = new int[maxCols];
        for (var c = 0; c < maxCols; c++)
            widths[c] = rows.Max(r => c < r.Count ? r[c].Length : 0);

        // 헤더
        sb.Append('|');
        for (var c = 0; c < maxCols; c++)
            sb.Append($" {rows[0][c].PadRight(widths[c])} |");
        sb.AppendLine();

        // 구분선
        sb.Append('|');
        for (var c = 0; c < maxCols; c++)
            sb.Append($" {new string('-', Math.Max(widths[c], 3))} |");
        sb.AppendLine();

        // 데이터 행
        for (var r = 1; r < rows.Count; r++)
        {
            sb.Append('|');
            for (var c = 0; c < maxCols; c++)
            {
                var cell = c < rows[r].Count ? rows[r][c] : "";
                sb.Append($" {cell.PadRight(widths[c])} |");
            }
            sb.AppendLine();
        }

        return sb.ToString().TrimEnd();
    }

    private static string ToCsv(List<List<string>> rows)
    {
        var sb = new StringBuilder();
        foreach (var row in rows)
        {
            sb.AppendLine(string.Join(",", row.Select(c =>
                c.Contains(',') || c.Contains('"') || c.Contains('\n')
                    ? $"\"{c.Replace("\"", "\"\"")}\"" : c)));
        }
        return sb.ToString().TrimEnd();
    }

    private static string ToHtml(List<List<string>> rows)
    {
        if (rows.Count == 0) return "";
        var sb = new StringBuilder();
        sb.AppendLine("<table>");

        // 헤더
        sb.AppendLine("  <thead><tr>");
        foreach (var cell in rows[0])
            sb.AppendLine($"    <th>{EscHtml(cell)}</th>");
        sb.AppendLine("  </tr></thead>");

        // 바디
        sb.AppendLine("  <tbody>");
        for (var r = 1; r < rows.Count; r++)
        {
            sb.AppendLine("  <tr>");
            foreach (var cell in rows[r])
                sb.AppendLine($"    <td>{EscHtml(cell)}</td>");
            sb.AppendLine("  </tr>");
        }
        sb.AppendLine("  </tbody>");
        sb.Append("</table>");
        return sb.ToString();
    }

    private static List<List<string>> Transpose(List<List<string>> rows)
    {
        if (rows.Count == 0) return rows;
        var maxCols = rows.Max(r => r.Count);
        var result  = new List<List<string>>();
        for (var c = 0; c < maxCols; c++)
        {
            var row = new List<string>();
            for (var r = 0; r < rows.Count; r++)
                row.Add(c < rows[r].Count ? rows[r][c] : "");
            result.Add(row);
        }
        return result;
    }

    private static List<List<string>> SortByColumn(List<List<string>> rows, int colIdx)
    {
        if (rows.Count <= 1) return rows;
        var header = rows[0];
        var data   = rows.Skip(1).ToList();
        data.Sort((a, b) =>
        {
            var va = colIdx < a.Count ? a[colIdx] : "";
            var vb = colIdx < b.Count ? b[colIdx] : "";
            // 숫자이면 숫자 비교
            if (double.TryParse(va, out var na) && double.TryParse(vb, out var nb))
                return na.CompareTo(nb);
            return string.Compare(va, vb, StringComparison.OrdinalIgnoreCase);
        });
        var result = new List<List<string>> { header };
        result.AddRange(data);
        return result;
    }

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

    private static void AddPreview(List<LauncherItem> items, string text)
    {
        var lines = text.Split('\n').Take(3);
        foreach (var line in lines)
        {
            var t = line.Length > 60 ? line[..60] + "…" : line;
            if (!string.IsNullOrWhiteSpace(t))
                items.Add(new LauncherItem(t, "", null, null, Symbol: "\uE81E"));
        }
    }

    private static string EscHtml(string s) =>
        s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;");
}
