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

namespace AxCopilot.Handlers;

/// <summary>
/// 색상 변환기 핸들러. "color" 프리픽스로 사용합니다.
/// 예: color #FF5500      → HEX / RGB / HSL 모두 표시
///     color 255,85,0     → HEX 변환
///     color red          → 색상 이름 → HEX
///     color hsl(24,100%,50%) → HSL → HEX / RGB
/// </summary>
public class ColorHandler : IActionHandler
{
    public string? Prefix => "color";

    public PluginMetadata Metadata => new(
        "Color",
        "색상 변환기 — color #FF5500 · color 255,85,0 · color red",
        "1.0",
        "AX");

    // ─── 색상 이름 사전 ─────────────────────────────────────────────────────
    private static readonly Dictionary<string, string> _namedColors = new(StringComparer.OrdinalIgnoreCase)
    {
        ["red"]        = "#FF0000", ["빨강"]    = "#FF0000", ["빨간색"] = "#FF0000",
        ["green"]      = "#008000", ["초록"]    = "#008000", ["초록색"] = "#008000",
        ["blue"]       = "#0000FF", ["파랑"]    = "#0000FF", ["파란색"] = "#0000FF",
        ["white"]      = "#FFFFFF", ["흰색"]    = "#FFFFFF", ["하양"]   = "#FFFFFF",
        ["black"]      = "#000000", ["검정"]    = "#000000", ["검은색"] = "#000000",
        ["yellow"]     = "#FFFF00", ["노랑"]    = "#FFFF00", ["노란색"] = "#FFFF00",
        ["orange"]     = "#FFA500", ["주황"]    = "#FFA500", ["주황색"] = "#FFA500",
        ["purple"]     = "#800080", ["보라"]    = "#800080", ["보라색"] = "#800080",
        ["pink"]       = "#FFC0CB", ["분홍"]    = "#FFC0CB", ["분홍색"] = "#FFC0CB",
        ["hotpink"]    = "#FF69B4", ["핫핑크"]  = "#FF69B4",
        ["cyan"]       = "#00FFFF", ["시안"]    = "#00FFFF",
        ["magenta"]    = "#FF00FF", ["마젠타"]  = "#FF00FF",
        ["brown"]      = "#A52A2A", ["갈색"]    = "#A52A2A",
        ["gray"]       = "#808080", ["grey"]   = "#808080", ["회색"] = "#808080", ["회"] = "#808080",
        ["silver"]     = "#C0C0C0", ["은색"]    = "#C0C0C0",
        ["gold"]       = "#FFD700", ["금색"]    = "#FFD700",
        ["navy"]       = "#000080", ["남색"]    = "#000080",
        ["teal"]       = "#008080", ["틸"]      = "#008080",
        ["lime"]       = "#00FF00", ["라임"]    = "#00FF00",
        ["maroon"]     = "#800000", ["밤색"]    = "#800000",
        ["olive"]      = "#808000", ["올리브"]  = "#808000",
        ["coral"]      = "#FF7F50", ["코랄"]    = "#FF7F50",
        ["salmon"]     = "#FA8072", ["연어색"]  = "#FA8072",
        ["skyblue"]    = "#87CEEB", ["하늘색"]  = "#87CEEB",
        ["lightblue"]  = "#ADD8E6", ["연파랑"]  = "#ADD8E6",
        ["darkblue"]   = "#00008B", ["진파랑"]  = "#00008B",
        ["darkgreen"]  = "#006400", ["진초록"]  = "#006400",
        ["lightgreen"] = "#90EE90", ["연초록"]  = "#90EE90",
        ["indigo"]     = "#4B0082", ["인디고"]  = "#4B0082",
        ["violet"]     = "#EE82EE", ["바이올렛"] = "#EE82EE",
        ["beige"]      = "#F5F5DC", ["베이지"]  = "#F5F5DC",
        ["ivory"]      = "#FFFFF0", ["아이보리"] = "#FFFFF0",
        ["khaki"]      = "#F0E68C", ["카키"]    = "#F0E68C",
        ["lavender"]   = "#E6E6FA", ["라벤더"]  = "#E6E6FA",
        ["turquoise"]  = "#40E0D0", ["터키옥"]  = "#40E0D0",
        ["chocolate"]  = "#D2691E", ["초콜릿"]  = "#D2691E",
        ["crimson"]    = "#DC143C", ["크림슨"]  = "#DC143C",
        ["transparent"] = "#00000000",
    };

    // ─── 정규식 ─────────────────────────────────────────────────────────────
    private static readonly Regex _hexRe  = new(@"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$");
    private static readonly Regex _rgbRe  = new(@"^(?:rgb\s*\()?\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)?$", RegexOptions.IgnoreCase);
    private static readonly Regex _rgbaRe = new(@"^rgba\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d.]+)\s*\)$", RegexOptions.IgnoreCase);
    private static readonly Regex _hslRe  = new(@"^hsl\s*\(\s*([\d.]+)\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*\)$", RegexOptions.IgnoreCase);

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        if (string.IsNullOrWhiteSpace(query))
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    "색상 코드를 입력하세요",
                    "예: #FF5500  ·  255,85,0  ·  red  ·  hsl(20,100%,50%)",
                    null, null, Symbol: Symbols.ColorPicker)
            ]);
        }

        var q = query.Trim();
        var items = new List<LauncherItem>();

        // HEX 형식
        if (_hexRe.IsMatch(q))
        {
            var hex = q.TrimStart('#');
            if (hex.Length == 3)
                hex = $"{hex[0]}{hex[0]}{hex[1]}{hex[1]}{hex[2]}{hex[2]}";

            int r, g, b;
            byte a = 255;

            if (hex.Length == 8)
            {
                a = Convert.ToByte(hex[..2], 16);
                r = Convert.ToInt32(hex[2..4], 16);
                g = Convert.ToInt32(hex[4..6], 16);
                b = Convert.ToInt32(hex[6..8], 16);
            }
            else
            {
                r = Convert.ToInt32(hex[..2], 16);
                g = Convert.ToInt32(hex[2..4], 16);
                b = Convert.ToInt32(hex[4..6], 16);
            }

            AddColorItems(items, r, g, b, a, $"#{hex.ToUpperInvariant()}");
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // RGB 형식
        var rgbM = _rgbRe.Match(q);
        if (rgbM.Success)
        {
            int r = int.Parse(rgbM.Groups[1].Value);
            int g = int.Parse(rgbM.Groups[2].Value);
            int b = int.Parse(rgbM.Groups[3].Value);
            if (r <= 255 && g <= 255 && b <= 255)
            {
                AddColorItems(items, r, g, b, 255, $"rgb({r},{g},{b})");
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
        }

        // RGBA 형식
        var rgbaM = _rgbaRe.Match(q);
        if (rgbaM.Success)
        {
            int r = int.Parse(rgbaM.Groups[1].Value);
            int g = int.Parse(rgbaM.Groups[2].Value);
            int b = int.Parse(rgbaM.Groups[3].Value);
            double aD = double.Parse(rgbaM.Groups[4].Value, System.Globalization.CultureInfo.InvariantCulture);
            byte a = (byte)Math.Clamp((int)(aD * 255), 0, 255);
            if (r <= 255 && g <= 255 && b <= 255)
            {
                AddColorItems(items, r, g, b, a, $"rgba({r},{g},{b},{aD:G3})");
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
        }

        // HSL 형식
        var hslM = _hslRe.Match(q);
        if (hslM.Success)
        {
            double h = double.Parse(hslM.Groups[1].Value, System.Globalization.CultureInfo.InvariantCulture);
            double s = double.Parse(hslM.Groups[2].Value, System.Globalization.CultureInfo.InvariantCulture) / 100;
            double l = double.Parse(hslM.Groups[3].Value, System.Globalization.CultureInfo.InvariantCulture) / 100;
            var (r, g, b) = HslToRgb(h, s, l);
            AddColorItems(items, r, g, b, 255, $"hsl({h:G},{s*100:G}%,{l*100:G}%)");
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 색상 이름
        if (_namedColors.TryGetValue(q, out var namedHex))
        {
            var hex = namedHex.TrimStart('#');
            int r = Convert.ToInt32(hex[..2], 16);
            int g = Convert.ToInt32(hex[2..4], 16);
            int b = Convert.ToInt32(hex[4..6], 16);
            AddColorItems(items, r, g, b, 255, namedHex.ToUpperInvariant());
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 검색 모드 (일부 색상 이름 검색)
        var searchQ = q.ToLowerInvariant();
        var matched = _namedColors
            .Where(kv => kv.Key.Contains(searchQ, StringComparison.OrdinalIgnoreCase))
            .Take(8);
        foreach (var kv in matched)
        {
            items.Add(new LauncherItem(
                $"{kv.Key}  →  {kv.Value.ToUpperInvariant()}",
                "Enter로 HEX 복사",
                null, kv.Value.ToUpperInvariant(), Symbol: Symbols.ColorPicker));
        }

        if (!items.Any())
        {
            items.Add(new LauncherItem(
                "인식할 수 없는 색상",
                "#RRGGBB · RGB(r,g,b) · hsl(h,s%,l%) · red 등 색상 이름",
                null, null, Symbol: Symbols.Error));
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is string value)
            try { Clipboard.SetText(value); } catch (Exception) { }
        return Task.CompletedTask;
    }

    // ─── 색상 항목 생성 ──────────────────────────────────────────────────────

    private static void AddColorItems(List<LauncherItem> items, int r, int g, int b, byte a, string source)
    {
        var hex     = a == 255
            ? $"#{r:X2}{g:X2}{b:X2}"
            : $"#{a:X2}{r:X2}{g:X2}{b:X2}";
        var rgb     = a == 255
            ? $"rgb({r}, {g}, {b})"
            : $"rgba({r}, {g}, {b}, {a / 255.0:G3})";
        var (h, s, l) = RgbToHsl(r, g, b);
        var hsl     = $"hsl({h:G3}, {s * 100:G3}%, {l * 100:G3}%)";
        var (hh, sv, v) = RgbToHsv(r, g, b);
        var hsv     = $"hsv({hh:G3}, {sv * 100:G3}%, {v * 100:G3}%)";

        items.Add(new LauncherItem($"HEX  →  {hex.ToUpperInvariant()}",  $"{source}  ·  Enter로 복사", null, hex.ToUpperInvariant(),  Symbol: Symbols.ColorPicker));
        items.Add(new LauncherItem($"RGB  →  {rgb}",   $"{source}  ·  Enter로 복사", null, rgb,   Symbol: Symbols.ColorPicker));
        items.Add(new LauncherItem($"HSL  →  {hsl}",   $"{source}  ·  Enter로 복사", null, hsl,   Symbol: Symbols.ColorPicker));
        items.Add(new LauncherItem($"HSV  →  {hsv}",   $"{source}  ·  Enter로 복사", null, hsv,   Symbol: Symbols.ColorPicker));
    }

    // ─── 색상 공간 변환 ───────────────────────────────────────────────────────

    private static (double h, double s, double l) RgbToHsl(int r, int g, int b)
    {
        double rf = r / 255.0, gf = g / 255.0, bf = b / 255.0;
        double max = Math.Max(rf, Math.Max(gf, bf));
        double min = Math.Min(rf, Math.Min(gf, bf));
        double l = (max + min) / 2;
        double h = 0, s = 0;

        if (max != min)
        {
            double d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            h = max == rf ? (gf - bf) / d + (gf < bf ? 6 : 0)
              : max == gf ? (bf - rf) / d + 2
              :              (rf - gf) / d + 4;
            h /= 6;
        }
        return (Math.Round(h * 360, 1), Math.Round(s, 4), Math.Round(l, 4));
    }

    private static (double h, double s, double v) RgbToHsv(int r, int g, int b)
    {
        double rf = r / 255.0, gf = g / 255.0, bf = b / 255.0;
        double max = Math.Max(rf, Math.Max(gf, bf));
        double min = Math.Min(rf, Math.Min(gf, bf));
        double v = max, s = 0, h = 0;
        double d = max - min;

        if (max != 0) s = d / max;
        if (d != 0)
        {
            h = max == rf ? (gf - bf) / d + (gf < bf ? 6 : 0)
              : max == gf ? (bf - rf) / d + 2
              :              (rf - gf) / d + 4;
            h /= 6;
        }
        return (Math.Round(h * 360, 1), Math.Round(s, 4), Math.Round(v, 4));
    }

    private static (int r, int g, int b) HslToRgb(double h, double s, double l)
    {
        double r, g, b;
        if (s == 0) { r = g = b = l; }
        else
        {
            double q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            double p = 2 * l - q;
            h /= 360;
            r = Hue2Rgb(p, q, h + 1.0 / 3);
            g = Hue2Rgb(p, q, h);
            b = Hue2Rgb(p, q, h - 1.0 / 3);
        }
        return ((int)Math.Round(r * 255), (int)Math.Round(g * 255), (int)Math.Round(b * 255));
    }

    private static double Hue2Rgb(double p, double q, double t)
    {
        if (t < 0) t += 1;
        if (t > 1) t -= 1;
        if (t < 1.0 / 6) return p + (q - p) * 6 * t;
        if (t < 1.0 / 2) return q;
        if (t < 2.0 / 3) return p + (q - p) * (2.0 / 3 - t) * 6;
        return p;
    }
}
