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

namespace AxCopilot.Handlers;

/// <summary>
/// L18-3: 화면 비율·해상도 계산기 핸들러. "aspect" 프리픽스로 사용합니다.
///
/// 예: aspect                 → 주요 비율 목록
///     aspect 1920 1080       → 1920x1080 비율 계산
///     aspect 16:9 1280       → 16:9 비율에서 너비 1280의 높이
///     aspect 16:9 h 720      → 16:9 비율에서 높이 720의 너비
///     aspect 4:3             → 4:3 비율의 주요 해상도 목록
///     aspect crop 1920 1080 4:3 → 크롭 영역 계산
/// Enter → 해상도 복사.
/// </summary>
public class AspectHandler : IActionHandler
{
    public string? Prefix => "aspect";

    public PluginMetadata Metadata => new(
        "Aspect",
        "화면 비율·해상도 계산기 — 16:9 · 4:3 · 21:9 · 크롭 영역",
        "1.0",
        "AX");

    private record AspectPreset(string Ratio, string Name, (int W, int H)[] Resolutions);

    private static readonly AspectPreset[] Presets =
    [
        new("16:9",  "와이드스크린 (모니터·TV·유튜브)",
            [(3840,2160),(2560,1440),(1920,1080),(1600,900),(1366,768),(1280,720),(960,540),(854,480),(640,360)]),

        new("4:3",   "전통 CRT·클래식 TV",
            [(2048,1536),(1600,1200),(1400,1050),(1280,960),(1024,768),(800,600),(640,480)]),

        new("21:9",  "울트라와이드 시네마",
            [(5120,2160),(3440,1440),(2560,1080),(2560,1080),(1280,540)]),

        new("1:1",   "정사각형 (인스타그램·SNS)",
            [(4096,4096),(2048,2048),(1080,1080),(720,720),(512,512)]),

        new("9:16",  "세로 (모바일·스토리·릴스)",
            [(1080,1920),(720,1280),(540,960),(360,640)]),

        new("3:2",   "DSLR 카메라 (35mm)",
            [(6000,4000),(4500,3000),(3000,2000),(1500,1000)]),

        new("2:1",   "시네마 와이드",
            [(4096,2048),(2048,1024),(1920,960)]),

        new("5:4",   "구형 모니터",
            [(1280,1024),(1024,819)]),

        new("2.35:1","영화 시네마스코프",
            [(2560,1090),(1920,817),(1280,544)]),
    ];

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

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("화면 비율·해상도 계산기",
                "예: aspect 1920 1080  /  aspect 16:9 1280  /  aspect 4:3",
                null, null, Symbol: "\uE7F4"));
            items.Add(new LauncherItem("── 주요 비율 ──", "", null, null, Symbol: "\uE7F4"));
            foreach (var p in Presets)
                items.Add(new LauncherItem($"{p.Ratio}  {p.Name}",
                    $"주요 해상도: {string.Join(", ", p.Resolutions.Take(3).Select(r => $"{r.W}×{r.H}"))}…",
                    null, null, Symbol: "\uE7F4"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var parts = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);

        // aspect <W> <H> → 비율 계산
        if (parts.Length >= 2 && int.TryParse(parts[0], out var w1) && int.TryParse(parts[1], out var h1))
        {
            items.AddRange(BuildFromResolution(w1, h1));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // aspect <비율> 형식 (예: 16:9, 4:3, 16/9)
        if (TryParseRatio(parts[0], out var rw, out var rh))
        {
            // aspect 16:9 <너비>  또는  aspect 16:9 h <높이>
            if (parts.Length >= 2)
            {
                var isHeight = parts.Length >= 3 &&
                    parts[1].ToLowerInvariant() is "h" or "height" or "높이";
                var dimStr   = isHeight ? parts[2] : parts[1];

                if (int.TryParse(dimStr, out var dim))
                {
                    if (isHeight)
                    {
                        var calcW = (int)Math.Round((double)dim * rw / rh);
                        items.AddRange(BuildFromRatioAndDim(rw, rh, calcW, dim));
                    }
                    else
                    {
                        var calcH = (int)Math.Round((double)dim * rh / rw);
                        items.AddRange(BuildFromRatioAndDim(rw, rh, dim, calcH));
                    }
                    return Task.FromResult<IEnumerable<LauncherItem>>(items);
                }
            }

            // aspect 16:9 → 주요 해상도 목록
            items.AddRange(BuildFromRatio(rw, rh));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // crop 서브커맨드
        if (parts[0].ToLowerInvariant() == "crop" && parts.Length >= 5)
        {
            if (int.TryParse(parts[1], out var srcW) &&
                int.TryParse(parts[2], out var srcH) &&
                TryParseRatio(parts[3], out var cRw, out var cRh))
            {
                items.AddRange(BuildCropItems(srcW, srcH, cRw, cRh));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
        }

        items.Add(new LauncherItem("형식 오류",
            "예: aspect 1920 1080  /  aspect 16:9 1280  /  aspect 16:9 h 720",
            null, null, Symbol: "\uE783"));
        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("Aspect", "클립보드에 복사했습니다.");
            }
            catch { }
        }
        return Task.CompletedTask;
    }

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

    private static List<LauncherItem> BuildFromResolution(int w, int h)
    {
        var items = new List<LauncherItem>();
        var gcd   = Gcd(w, h);
        var rw    = w / gcd;
        var rh    = h / gcd;
        var ratio = $"{rw}:{rh}";
        var frac  = (double)w / h;

        items.Add(new LauncherItem($"{w} × {h}  →  비율 {ratio}",
            $"소수 비율: {frac:F4}", null, ("copy", ratio), Symbol: "\uE7F4"));
        items.Add(new LauncherItem($"비율",         ratio,              null, ("copy", ratio),        Symbol: "\uE7F4"));
        items.Add(new LauncherItem($"소수 비율",    $"{frac:F4}",       null, ("copy", $"{frac:F4}"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem($"픽셀 수",      $"{(long)w * h:N0} px ({(long)w * h / 1_000_000.0:F1} MP)",
            null, null, Symbol: "\uE7F4"));

        // 비슷한 프리셋 찾기
        var preset = Presets.FirstOrDefault(p => p.Ratio == ratio);
        if (preset != null)
        {
            items.Add(new LauncherItem($"── {preset.Ratio}  {preset.Name} ──", "", null, null, Symbol: "\uE7F4"));
            foreach (var (pw, ph) in preset.Resolutions)
                items.Add(new LauncherItem($"{pw} × {ph}", FormatPixels(pw, ph),
                    null, ("copy", $"{pw}x{ph}"), Symbol: "\uE7F4"));
        }
        else
        {
            // 같은 비율의 다른 해상도 계산
            items.Add(new LauncherItem("── 같은 비율 기타 해상도 ──", "", null, null, Symbol: "\uE7F4"));
            var scales = new[] { 0.25, 0.5, 0.75, 1.25, 1.5, 2.0 };
            foreach (var s in scales)
            {
                var sw = (int)Math.Round(w * s / gcd) * gcd;
                var sh = (int)Math.Round(h * s / gcd) * gcd;
                if (sw > 0 && sh > 0)
                    items.Add(new LauncherItem($"{sw} × {sh}  ({s:P0})",
                        FormatPixels(sw, sh), null, ("copy", $"{sw}x{sh}"), Symbol: "\uE7F4"));
            }
        }
        return items;
    }

    private static List<LauncherItem> BuildFromRatio(int rw, int rh)
    {
        var items  = new List<LauncherItem>();
        var preset = Presets.FirstOrDefault(p => p.Ratio == $"{rw}:{rh}");

        if (preset != null)
        {
            items.Add(new LauncherItem($"{preset.Ratio}  {preset.Name}",
                $"주요 해상도 {preset.Resolutions.Length}개", null, null, Symbol: "\uE7F4"));
            foreach (var (pw, ph) in preset.Resolutions)
                items.Add(new LauncherItem($"{pw} × {ph}", FormatPixels(pw, ph),
                    null, ("copy", $"{pw}x{ph}"), Symbol: "\uE7F4"));
        }
        else
        {
            items.Add(new LauncherItem($"{rw}:{rh} 비율",
                "자주 쓰는 너비 기준 해상도", null, null, Symbol: "\uE7F4"));
            var widths = new[] { 640, 1280, 1920, 2560, 3840 };
            foreach (var bw in widths)
            {
                var bh = (int)Math.Round((double)bw * rh / rw);
                items.Add(new LauncherItem($"{bw} × {bh}", FormatPixels(bw, bh),
                    null, ("copy", $"{bw}x{bh}"), Symbol: "\uE7F4"));
            }
        }
        return items;
    }

    private static List<LauncherItem> BuildFromRatioAndDim(int rw, int rh, int w, int h)
    {
        var items = new List<LauncherItem>();
        var label = $"{rw}:{rh}  →  {w} × {h}";
        items.Add(new LauncherItem(label,
            $"픽셀 {(long)w * h:N0}  · Enter 복사", null, ("copy", $"{w}x{h}"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem($"너비",  $"{w} px", null, ("copy", $"{w}"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem($"높이",  $"{h} px", null, ("copy", $"{h}"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem("CSS",    $"{w}px × {h}px", null, ("copy", $"{w}px × {h}px"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem("w×h",    $"{w}x{h}", null, ("copy", $"{w}x{h}"), Symbol: "\uE7F4"));
        return items;
    }

    private static List<LauncherItem> BuildCropItems(int srcW, int srcH, int cRw, int cRh)
    {
        var items = new List<LauncherItem>();
        // 크롭 방향 결정
        var srcRatio  = (double)srcW / srcH;
        var cropRatio = (double)cRw  / cRh;

        int cropW, cropH, offsetX, offsetY;
        if (srcRatio > cropRatio)
        {
            // 좌우 크롭
            cropH = srcH;
            cropW = (int)Math.Round(srcH * cropRatio);
            offsetX = (srcW - cropW) / 2;
            offsetY = 0;
        }
        else
        {
            // 상하 크롭
            cropW = srcW;
            cropH = (int)Math.Round(srcW / cropRatio);
            offsetX = 0;
            offsetY = (srcH - cropH) / 2;
        }

        items.Add(new LauncherItem($"크롭: {srcW}×{srcH} → {cRw}:{cRh}",
            $"크롭 영역: {cropW}×{cropH}  오프셋: ({offsetX},{offsetY})",
            null, ("copy", $"{cropW}x{cropH}"), Symbol: "\uE7F4"));
        items.Add(new LauncherItem("크롭 크기",  $"{cropW} × {cropH}",          null, ("copy", $"{cropW}x{cropH}"),          Symbol: "\uE7F4"));
        items.Add(new LauncherItem("X 오프셋",   $"{offsetX} px",               null, ("copy", $"{offsetX}"),                 Symbol: "\uE7F4"));
        items.Add(new LauncherItem("Y 오프셋",   $"{offsetY} px",               null, ("copy", $"{offsetY}"),                 Symbol: "\uE7F4"));
        items.Add(new LauncherItem("FFmpeg crop", $"crop={cropW}:{cropH}:{offsetX}:{offsetY}",
            null, ("copy", $"crop={cropW}:{cropH}:{offsetX}:{offsetY}"), Symbol: "\uE7F4"));
        return items;
    }

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

    private static bool TryParseRatio(string s, out int rw, out int rh)
    {
        rw = rh = 0;
        var sep = s.Contains(':') ? ':' : s.Contains('/') ? '/' : '\0';
        if (sep == '\0') return false;
        var parts = s.Split(sep);
        if (parts.Length != 2) return false;
        return double.TryParse(parts[0], System.Globalization.NumberStyles.Any,
                   System.Globalization.CultureInfo.InvariantCulture, out var drw) &&
               double.TryParse(parts[1], System.Globalization.NumberStyles.Any,
                   System.Globalization.CultureInfo.InvariantCulture, out var drh) &&
               (rw = (int)Math.Round(drw * 100)) > 0 &&
               (rh = (int)Math.Round(drh * 100)) > 0;
    }

    private static int Gcd(int a, int b) => b == 0 ? a : Gcd(b, a % b);

    private static string FormatPixels(int w, int h)
    {
        var mp = (long)w * h / 1_000_000.0;
        return $"{(long)w * h:N0} px  ({mp:F1} MP)";
    }
}
