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

namespace AxCopilot.Handlers;

/// <summary>
/// L11-1: CSV 뷰어·파서 핸들러. "csv" 프리픽스로 사용합니다.
///
/// 예: csv                   → 클립보드 CSV 파싱 (헤더·행수·컬럼수)
///     csv col 2             → 2번째 컬럼 값 목록 추출
///     csv row 3             → 3번째 행 출력
///     csv stats             → 숫자 컬럼 합계·평균·최대·최소
///     csv head              → 헤더 컬럼명 목록
///     csv tsv               → CSV → TSV(탭 구분) 변환
/// Enter → 결과를 클립보드에 복사.
/// </summary>
public class CsvHandler : IActionHandler
{
    public string? Prefix => "csv";

    public PluginMetadata Metadata => new(
        "CSV",
        "CSV 뷰어·파서 — 컬럼 추출 · 통계 · 형식 변환",
        "1.0",
        "AX");

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

        var clip  = GetClipboard();
        var hasData = !string.IsNullOrWhiteSpace(clip) && LooksCsv(clip);

        if (string.IsNullOrWhiteSpace(q))
        {
            if (hasData)
            {
                items.AddRange(BuildOverviewItems(clip));
            }
            else
            {
                items.Add(new LauncherItem("CSV 뷰어", "CSV를 클립보드에 복사 후 'csv' 입력",
                    null, null, Symbol: "\uE8A5"));
                items.Add(new LauncherItem("csv col 2",  "2번째 컬럼 추출", null, null, Symbol: "\uE8A5"));
                items.Add(new LauncherItem("csv stats",  "숫자 컬럼 통계",  null, null, Symbol: "\uE8A5"));
                items.Add(new LauncherItem("csv tsv",    "CSV → TSV 변환",  null, null, Symbol: "\uE8A5"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        if (!hasData)
        {
            items.Add(new LauncherItem("클립보드에 CSV 없음",
                "CSV 형식 데이터를 클립보드에 복사 후 시도하세요", null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var rows    = ParseCsv(clip);
        if (rows.Count == 0)
        {
            items.Add(new LauncherItem("파싱 실패", "유효한 CSV가 아닙니다", null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        switch (sub)
        {
            case "col":
            case "column":
            {
                var colIdx = parts.Length > 1 && int.TryParse(parts[1], out var n) ? n - 1 : 0;
                items.AddRange(ExtractColumn(rows, colIdx));
                break;
            }
            case "row":
            {
                var rowIdx = parts.Length > 1 && int.TryParse(parts[1], out var n) ? n - 1 : 0;
                items.AddRange(ExtractRow(rows, rowIdx));
                break;
            }
            case "stats":
            case "stat":
            {
                items.AddRange(BuildStatsItems(rows));
                break;
            }
            case "head":
            case "header":
            {
                if (rows.Count > 0)
                {
                    var header = rows[0];
                    var all    = string.Join(", ", header);
                    items.Add(new LauncherItem($"헤더  {header.Count}개 컬럼", all, null, ("copy", all), Symbol: "\uE8A5"));
                    for (var i = 0; i < header.Count; i++)
                        items.Add(new LauncherItem($"[{i+1}] {header[i]}", $"컬럼 {i+1}", null, ("copy", header[i]), Symbol: "\uE8A5"));
                }
                break;
            }
            case "tsv":
            {
                var tsv = ConvertToTsv(rows);
                items.Add(new LauncherItem(
                    $"TSV 변환  {rows.Count}행",
                    "탭 구분자  · Enter 복사",
                    null, ("copy", tsv), Symbol: "\uE8A5"));
                break;
            }
            default:
                items.AddRange(BuildOverviewItems(clip));
                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("CSV", "클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
        }
        return Task.CompletedTask;
    }

    // ── 빌더 ─────────────────────────────────────────────────────────────────

    private static IEnumerable<LauncherItem> BuildOverviewItems(string csv)
    {
        var rows = ParseCsv(csv);
        if (rows.Count == 0)
        {
            yield return new LauncherItem("파싱 실패", "유효한 CSV 데이터가 아닙니다", null, null, Symbol: "\uE783");
            yield break;
        }

        var headerRow  = rows[0];
        var dataRows   = rows.Count > 1 ? rows.Count - 1 : 0;
        var colCount   = headerRow.Count;

        yield return new LauncherItem(
            $"CSV  {dataRows}행 × {colCount}열",
            $"헤더: {string.Join(", ", headerRow.Take(5))}{(colCount > 5 ? " …" : "")}",
            null,
            ("copy", csv),
            Symbol: "\uE8A5");

        yield return new LauncherItem("컬럼 수",    $"{colCount}개",        null, null, Symbol: "\uE8A5");
        yield return new LauncherItem("데이터 행수", $"{dataRows}행",        null, null, Symbol: "\uE8A5");
        yield return new LauncherItem("헤더",        string.Join(" | ", headerRow.Take(8)), null,
            ("copy", string.Join(",", headerRow)), Symbol: "\uE8A5");

        // 첫 데이터 행 미리보기
        if (rows.Count > 1)
        {
            var first = rows[1];
            yield return new LauncherItem(
                "첫 번째 행",
                string.Join(" | ", first.Take(6)),
                null,
                ("copy", string.Join(",", first)),
                Symbol: "\uE8A5");
        }
    }

    private static IEnumerable<LauncherItem> ExtractColumn(List<List<string>> rows, int colIdx)
    {
        if (rows.Count == 0)
        {
            yield return new LauncherItem("데이터 없음", "", null, null, Symbol: "\uE783");
            yield break;
        }

        var maxCol = rows.Max(r => r.Count) - 1;
        colIdx = Math.Clamp(colIdx, 0, maxCol);

        var header  = rows[0].Count > colIdx ? rows[0][colIdx] : $"컬럼{colIdx+1}";
        var values  = rows.Skip(1).Where(r => r.Count > colIdx).Select(r => r[colIdx]).ToList();
        var allText = string.Join("\n", values);

        yield return new LauncherItem(
            $"[{colIdx+1}] {header}  ({values.Count}개 값)",
            "전체 복사: Enter",
            null, ("copy", allText), Symbol: "\uE8A5");

        foreach (var v in values.Take(15))
            yield return new LauncherItem(v, $"컬럼: {header}", null, ("copy", v), Symbol: "\uE8A5");
    }

    private static IEnumerable<LauncherItem> ExtractRow(List<List<string>> rows, int rowIdx)
    {
        rowIdx = Math.Clamp(rowIdx, 0, rows.Count - 1);
        var row     = rows[rowIdx];
        var header  = rows[0];
        var allText = string.Join(",", row);

        yield return new LauncherItem(
            $"행 {rowIdx+1}  ({row.Count}개 값)",
            allText.Length > 80 ? allText[..80] + "…" : allText,
            null, ("copy", allText), Symbol: "\uE8A5");

        for (var i = 0; i < row.Count; i++)
        {
            var colName = header.Count > i ? header[i] : $"컬럼{i+1}";
            yield return new LauncherItem($"[{colName}]", row[i], null, ("copy", row[i]), Symbol: "\uE8A5");
        }
    }

    private static IEnumerable<LauncherItem> BuildStatsItems(List<List<string>> rows)
    {
        if (rows.Count < 2)
        {
            yield return new LauncherItem("데이터 없음", "헤더 포함 2행 이상 필요", null, null, Symbol: "\uE783");
            yield break;
        }

        var header = rows[0];
        var data   = rows.Skip(1).ToList();

        for (var col = 0; col < header.Count; col++)
        {
            var colName = header.Count > col ? header[col] : $"컬럼{col+1}";
            var nums    = data
                .Where(r => r.Count > col)
                .Select(r => r[col])
                .Where(v => double.TryParse(v, System.Globalization.NumberStyles.Any,
                                            System.Globalization.CultureInfo.InvariantCulture, out _))
                .Select(v => double.Parse(v, System.Globalization.CultureInfo.InvariantCulture))
                .ToList();

            if (nums.Count == 0) continue;

            var sum = nums.Sum();
            var avg = nums.Average();
            var min = nums.Min();
            var max = nums.Max();

            yield return new LauncherItem(
                $"[{colName}]  합계: {sum:N2}",
                $"평균: {avg:N2}  최소: {min:N2}  최대: {max:N2}  ({nums.Count}개)",
                null,
                ("copy", $"{colName}: sum={sum:N2} avg={avg:N2} min={min:N2} max={max:N2}"),
                Symbol: "\uE8A5");
        }
    }

    // ── 변환 헬퍼 ────────────────────────────────────────────────────────────

    private static string ConvertToTsv(List<List<string>> rows)
    {
        var sb = new StringBuilder();
        foreach (var row in rows)
        {
            sb.AppendLine(string.Join("\t", row.Select(EscapeTsv)));
        }
        return sb.ToString().TrimEnd();
    }

    private static string EscapeTsv(string v) => v.Replace("\t", " ").Replace("\r", "").Replace("\n", " ");

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

    private static List<List<string>> ParseCsv(string text)
    {
        var result = new List<List<string>>();
        // 구분자 자동 감지 (탭 또는 쉼표)
        var firstLine = text.Split('\n')[0];
        var delimiter = firstLine.Count(c => c == '\t') > firstLine.Count(c => c == ',') ? '\t' : ',';

        using var reader = new System.IO.StringReader(text);
        string? line;
        while ((line = reader.ReadLine()) != null)
        {
            if (string.IsNullOrWhiteSpace(line)) continue;
            result.Add(ParseCsvLine(line, delimiter));
        }
        return result;
    }

    private static List<string> ParseCsvLine(string line, char delim)
    {
        var fields = new List<string>();
        var sb     = new StringBuilder();
        var inQuote = false;

        for (var i = 0; i < line.Length; i++)
        {
            var c = line[i];
            if (inQuote)
            {
                if (c == '"')
                {
                    if (i + 1 < line.Length && line[i + 1] == '"')
                    { sb.Append('"'); i++; }
                    else
                    { inQuote = false; }
                }
                else { sb.Append(c); }
            }
            else
            {
                if (c == '"')       { inQuote = true; }
                else if (c == delim){ fields.Add(sb.ToString()); sb.Clear(); }
                else                { sb.Append(c); }
            }
        }
        fields.Add(sb.ToString());
        return fields;
    }

    private static bool LooksCsv(string text)
    {
        var firstLine = text.Split('\n').FirstOrDefault(l => !string.IsNullOrWhiteSpace(l)) ?? "";
        return firstLine.Contains(',') || firstLine.Contains('\t');
    }

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