using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Windows;

namespace AxCopilot.Handlers;

// ─── 단위 변환 ─────────────────────────────────────────────────────────────────

/// <summary>
/// "100km in miles", "32f in c", "5lb to kg" 형식의 단위 변환.
/// </summary>
internal static class UnitConverter
{
    // 패턴: <숫자> <단위> in|to <단위>
    private static readonly Regex Pattern = new(
        @"^(-?\d+(?:\.\d+)?)\s*([a-z°/²³µ]+)\s+(?:in|to)\s+([a-z°/²³µ]+)$",
        RegexOptions.IgnoreCase | RegexOptions.Compiled);

    public static bool TryConvert(string input, out string? result)
    {
        result = null;
        var m = Pattern.Match(input.Trim());
        if (!m.Success) return false;

        if (!double.TryParse(m.Groups[1].Value,
                System.Globalization.NumberStyles.Float,
                System.Globalization.CultureInfo.InvariantCulture,
                out var value))
            return false;

        var from = m.Groups[2].Value.ToLowerInvariant();
        var to   = m.Groups[3].Value.ToLowerInvariant();

        // 온도는 비선형 → 별도 처리
        if (TryConvertTemperature(value, from, to, out var tResult))
        {
            result = $"{FormatNum(tResult)} {TemperatureLabel(to)}";
            return true;
        }

        // 나머지 범주(선형 변환)
        foreach (var table in _tables)
        {
            if (table.TryGetValue(from, out var fromFactor) &&
                table.TryGetValue(to,   out var toFactor))
            {
                var converted = value * fromFactor / toFactor;
                result = $"{FormatNum(converted)} {to}";
                return true;
            }
        }

        return false;
    }

    // ─── 온도 ────────────────────────────────────────────────────────────────

    private static bool TryConvertTemperature(double v, string from, string to, out double r)
    {
        r = 0;
        // 섭씨 표준화
        double celsius;
        switch (from)
        {
            case "c": case "°c": case "celsius":    celsius = v; break;
            case "f": case "°f": case "fahrenheit": celsius = (v - 32) * 5 / 9; break;
            case "k": case "kelvin":                celsius = v - 273.15; break;
            default: return false;
        }
        switch (to)
        {
            case "c": case "°c": case "celsius":    r = celsius; break;
            case "f": case "°f": case "fahrenheit": r = celsius * 9 / 5 + 32; break;
            case "k": case "kelvin":                r = celsius + 273.15; break;
            default: return false;
        }
        return true;
    }

    private static string TemperatureLabel(string unit) => unit switch
    {
        "c" or "°c" or "celsius"    => "°C",
        "f" or "°f" or "fahrenheit" => "°F",
        "k" or "kelvin"             => "K",
        _                           => unit
    };

    // ─── 선형 변환 테이블 (기준 단위 = 1) ────────────────────────────────────

    // 길이 (기준: m)
    private static readonly Dictionary<string, double> _length = new()
    {
        ["km"] = 1000, ["m"] = 1, ["cm"] = 0.01, ["mm"] = 0.001,
        ["mi"] = 1609.344, ["mile"] = 1609.344, ["miles"] = 1609.344,
        ["ft"] = 0.3048, ["feet"] = 0.3048, ["foot"] = 0.3048,
        ["in"] = 0.0254, ["inch"] = 0.0254, ["inches"] = 0.0254,
        ["yd"] = 0.9144, ["yard"] = 0.9144, ["yards"] = 0.9144,
        ["nm"] = 1e-9,
    };

    // 무게 (기준: kg)
    private static readonly Dictionary<string, double> _weight = new()
    {
        ["t"] = 1000, ["ton"] = 1000, ["tonnes"] = 1000,
        ["kg"] = 1, ["g"] = 0.001, ["mg"] = 1e-6,
        ["lb"] = 0.453592, ["lbs"] = 0.453592, ["pound"] = 0.453592, ["pounds"] = 0.453592,
        ["oz"] = 0.0283495, ["ounce"] = 0.0283495, ["ounces"] = 0.0283495,
    };

    // 속도 (기준: m/s)
    private static readonly Dictionary<string, double> _speed = new()
    {
        ["m/s"] = 1, ["mps"] = 1,
        ["km/h"] = 1.0 / 3.6, ["kmh"] = 1.0 / 3.6, ["kph"] = 1.0 / 3.6,
        ["mph"] = 0.44704,
        ["kn"] = 0.514444, ["knot"] = 0.514444, ["knots"] = 0.514444,
    };

    // 데이터 (기준: byte)
    private static readonly Dictionary<string, double> _data = new()
    {
        ["b"] = 1, ["byte"] = 1, ["bytes"] = 1,
        ["kb"] = 1024, ["kib"] = 1024,
        ["mb"] = 1024 * 1024, ["mib"] = 1024 * 1024,
        ["gb"] = 1024.0 * 1024 * 1024, ["gib"] = 1024.0 * 1024 * 1024,
        ["tb"] = 1024.0 * 1024 * 1024 * 1024, ["tib"] = 1024.0 * 1024 * 1024 * 1024,
        ["pb"] = 1024.0 * 1024 * 1024 * 1024 * 1024,
    };

    // 넓이 (기준: m²)
    private static readonly Dictionary<string, double> _area = new()
    {
        ["m²"] = 1, ["m2"] = 1,
        ["km²"] = 1e6, ["km2"] = 1e6,
        ["cm²"] = 1e-4, ["cm2"] = 1e-4,
        ["ha"] = 10000,
        ["acre"] = 4046.86, ["acres"] = 4046.86,
        ["ft²"] = 0.092903, ["ft2"] = 0.092903,
    };

    private static readonly List<Dictionary<string, double>> _tables = new()
        { _length, _weight, _speed, _data, _area };

    private static string FormatNum(double v)
    {
        if (v == Math.Floor(v) && Math.Abs(v) < 1e12)
            return ((long)v).ToString("N0", System.Globalization.CultureInfo.CurrentCulture);
        return v.ToString("G6", System.Globalization.CultureInfo.InvariantCulture);
    }

    // ─── 자동 제안 (목표 단위 없이 입력 시) ──────────────────────────────────

    // 패턴: <숫자><단위>  (공백 없어도 OK)
    private static readonly Regex _autoPattern = new(
        @"^(-?\d+(?:\.\d+)?)\s*([a-z°/²³µ]+)$",
        RegexOptions.IgnoreCase | RegexOptions.Compiled);

    // 단위 → 주요 변환 대상 목록 (사용자에게 자동 제안)
    private static readonly Dictionary<string, string[]> _suggestions = new(StringComparer.OrdinalIgnoreCase)
    {
        // 길이
        ["km"]    = ["miles", "m", "ft"],
        ["miles"] = ["km", "m", "ft"],
        ["m"]     = ["km", "ft", "inches"],
        ["cm"]    = ["inches", "m"],
        ["mm"]    = ["inches", "cm"],
        ["ft"]    = ["m", "km", "inches"],
        ["feet"]  = ["m", "km", "inches"],
        ["in"]    = ["cm", "m"],
        ["inches"]= ["cm", "m"],
        // 무게
        ["kg"]    = ["lb", "g"],
        ["lb"]    = ["kg", "g"],
        ["lbs"]   = ["kg", "g"],
        ["g"]     = ["kg", "oz"],
        ["oz"]    = ["g", "kg"],
        // 속도
        ["km/h"]  = ["mph", "m/s"],
        ["kmh"]   = ["mph", "m/s"],
        ["kph"]   = ["mph", "m/s"],
        ["mph"]   = ["km/h", "m/s"],
        ["m/s"]   = ["km/h", "mph"],
        // 데이터
        ["mb"]    = ["gb", "kb"],
        ["gb"]    = ["mb", "tb"],
        ["tb"]    = ["gb", "mb"],
        ["kb"]    = ["mb", "b"],
        // 온도 — 양방향
        ["c"]     = ["f", "k"],
        ["°c"]    = ["°f", "k"],
        ["celsius"]= ["fahrenheit", "kelvin"],
        ["f"]     = ["c", "k"],
        ["°f"]    = ["°c", "k"],
        ["fahrenheit"] = ["celsius", "kelvin"],
    };

    /// <summary>
    /// "20km", "100f" 처럼 목표 단위 없이 입력하면 주요 변환 대상을 자동 제안합니다.
    /// </summary>
    public static List<LauncherItem> AutoSuggest(string input)
    {
        var m = _autoPattern.Match(input.Trim());
        if (!m.Success) return new();

        if (!double.TryParse(m.Groups[1].Value,
                System.Globalization.NumberStyles.Float,
                System.Globalization.CultureInfo.InvariantCulture,
                out var value))
            return new();

        var fromUnit = m.Groups[2].Value;
        if (!_suggestions.TryGetValue(fromUnit, out var targets)) return new();

        var items = new List<LauncherItem>();
        foreach (var to in targets)
        {
            if (TryConvert($"{value} {fromUnit} in {to}", out var r) && r != null)
            {
                items.Add(new LauncherItem(
                    r,
                    $"{value} {fromUnit} → {to}  ·  Enter로 복사",
                    null, r, Symbol: Symbols.Calculator));
            }
        }
        return items;
    }
}

// ─── = 접두어에서 today 날짜 단축 계산 ────────────────────────────────────────

/// <summary>
/// "today+30d", "today-7d", "today+2w" 등 날짜 단축 패턴을 = 핸들러에서 처리합니다.
/// DateCalcHandler의 로직을 재사용합니다.
/// </summary>
internal static class DateShortcut
{
    private static readonly Regex _pattern = new(
        @"^today\s*([+-])(\d+)([dDwWmMyY])$",
        RegexOptions.IgnoreCase | RegexOptions.Compiled);

    public static bool TryMatch(string input, out IEnumerable<LauncherItem>? items)
    {
        items = null;
        var m = _pattern.Match(input.Trim());
        if (!m.Success) return false;

        var sign  = m.Groups[1].Value == "+" ? 1 : -1;
        var val   = int.Parse(m.Groups[2].Value) * sign;
        var unit  = m.Groups[3].Value.ToLowerInvariant();
        var now   = DateTime.Now;

        var target = unit switch
        {
            "d" => now.AddDays(val),
            "w" => now.AddDays(val * 7),
            "m" => now.AddMonths(val),
            "y" => now.AddYears(val),
            _   => now.AddDays(val),
        };

        var diff     = (target.Date - now.Date).Days;
        var dayName  = target.ToString("dddd", new System.Globalization.CultureInfo("ko-KR"));
        var dateStr  = target.ToString("yyyy-MM-dd");
        var diffText = diff == 0 ? "오늘"
                     : diff > 0 ? $"+{diff}일 후"
                     : $"{-diff}일 전";

        items = new List<LauncherItem>
        {
            new LauncherItem(
                $"{dateStr} ({dayName})",
                $"{input}  →  {diffText}  ·  Enter로 복사",
                null, dateStr, Symbol: Symbols.Calculator),
        };
        return true;
    }
}
