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

namespace AxCopilot.Handlers;

/// <summary>
/// L23-3: 근무 시간·급여 계산. "work" 프리픽스로 사용합니다.
///
/// 예: work 09:00 18:30           → 근무시간·초과근무 (점심 1시간 자동 제외)
///     work 09:00 18:30 -30       → 점심 30분 제외
///     work 09:00 18:30 -0        → 점심 제외 없음
///     work 09:00 18:30 pay 15000 → 급여 함께 계산
///     work pay 15000             → 이전 계산 재활용 급여 산출
///     work week 45.5             → 주간 근무시간 입력 → 초과 계산
/// Enter → 결과 복사
/// </summary>
public class WorkTimeHandler : IActionHandler
{
    public string? Prefix => "work";

    public PluginMetadata Metadata => new(
        "근무시간 계산",
        "출퇴근 시간 입력 → 근무시간·초과근무·급여 계산",
        "1.0",
        "AX");

    // 마지막 계산 캐시 (pay 재활용용)
    private static double _lastWorkedHours;

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

    private static bool TryParseTime(string s, out TimeSpan result)
    {
        result = default;
        s = s.Trim();
        // HH:mm or H:mm
        if (s.Contains(':'))
        {
            var parts = s.Split(':');
            if (parts.Length == 2 &&
                int.TryParse(parts[0], out var h) &&
                int.TryParse(parts[1], out var m) &&
                h >= 0 && h <= 47 && m >= 0 && m < 60)
            {
                result = new TimeSpan(h, m, 0);
                return true;
            }
            return false;
        }
        // HHmm (4자리)
        if (s.Length == 4 &&
            int.TryParse(s[..2], out var hh) &&
            int.TryParse(s[2..], out var mm) &&
            hh >= 0 && hh <= 23 && mm >= 0 && mm < 60)
        {
            result = new TimeSpan(hh, mm, 0);
            return true;
        }
        return false;
    }

    private static bool TryParseWorkTime(string q,
        out TimeSpan start, out TimeSpan end,
        out double lunchMinutes, out double payWage)
    {
        start        = default;
        end          = default;
        lunchMinutes = 60;
        payWage      = 0;

        var tokens = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        if (tokens.Length < 2) return false;
        if (!TryParseTime(tokens[0], out start)) return false;
        if (!TryParseTime(tokens[1], out end))   return false;

        for (var i = 2; i < tokens.Length; i++)
        {
            var t = tokens[i];
            // -N → 점심 제외 분
            if (t.StartsWith('-') && double.TryParse(t[1..],
                System.Globalization.NumberStyles.Any,
                System.Globalization.CultureInfo.InvariantCulture, out var lm))
            {
                lunchMinutes = lm;
            }
            // pay N
            else if (t.Equals("pay", StringComparison.OrdinalIgnoreCase) && i + 1 < tokens.Length)
            {
                if (double.TryParse(tokens[i + 1],
                    System.Globalization.NumberStyles.Any,
                    System.Globalization.CultureInfo.InvariantCulture, out var pw))
                {
                    payWage = pw;
                    i++;
                }
            }
        }
        return true;
    }

    private static (double stdPay, double otPay, double total) CalcPay(double wage, double workedHours)
    {
        var stdHours = Math.Min(workedHours, 8.0);
        var otHours  = Math.Max(0, workedHours - 8.0);
        var stdPay   = stdHours * wage;
        var otPay    = otHours  * wage * 1.5;
        return (stdPay, otPay, stdPay + otPay);
    }

    // ── GetItemsAsync ─────────────────────────────────────────────────────────

    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("근무시간 계산기",
                "work 09:00 18:30 → 근무시간  /  work 09:00 18:30 -30 → 점심 30분  /  work 09:00 18:30 pay 15000 → 급여",
                null, null, Symbol: "\uE916"));
            items.Add(new LauncherItem("work 09:00 18:30", "점심 1시간 자동 제외", null, null, Symbol: "\uE916"));
            items.Add(new LauncherItem("work 09:00 18:30 -30", "점심 30분 제외", null, null, Symbol: "\uE916"));
            items.Add(new LauncherItem("work pay 15000", "이전 계산 재활용 급여 산출", null, null, Symbol: "\uE916"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        // pay N → 이전 계산 재활용
        if (sub == "pay")
        {
            if (tokens.Length >= 2 && double.TryParse(tokens[1],
                System.Globalization.NumberStyles.Any,
                System.Globalization.CultureInfo.InvariantCulture, out var wage))
            {
                if (_lastWorkedHours <= 0)
                {
                    items.Add(new LauncherItem("이전 계산 없음", "먼저 시간을 계산하세요: work HH:mm HH:mm",
                        null, null, Symbol: "\uE783"));
                }
                else
                {
                    var (stdPay, otPay, total) = CalcPay(wage, _lastWorkedHours);
                    var result = $"근무 {_lastWorkedHours:F1}시간 | 시급 {wage:#,0}원 | 기본 {stdPay:#,0}원 | 초과 {otPay:#,0}원 | 합계 {total:#,0}원";
                    items.Add(new LauncherItem(
                        $"급여: {total:#,0}원",
                        $"기본 {stdPay:#,0}원 + 초과(1.5배) {otPay:#,0}원  ·  Enter: 복사",
                        null, ("copy", result), Symbol: "\uE916"));
                }
            }
            else
            {
                items.Add(new LauncherItem("시급을 입력하세요", "예: work pay 15000", null, null, Symbol: "\uE783"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // week N → 주간 근무시간
        if (sub == "week")
        {
            if (tokens.Length >= 2 && double.TryParse(tokens[1],
                System.Globalization.NumberStyles.Any,
                System.Globalization.CultureInfo.InvariantCulture, out var weekHours))
            {
                var std   = 40.0;
                var ot    = Math.Max(0, weekHours - std);
                var label = $"주간 근무 {weekHours:F1}시간  초과근무 {ot:F1}시간 (기준 {std}h)";
                items.Add(new LauncherItem(label, "Enter: 복사",
                    null, ("copy", label), Symbol: "\uE916"));
            }
            else
            {
                items.Add(new LauncherItem("시간을 입력하세요", "예: work week 45.5", null, null, Symbol: "\uE783"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 시각 파싱 시도
        if (!TryParseWorkTime(q, out var start, out var end, out var lunch, out var pay))
        {
            items.Add(new LauncherItem("시간 형식 오류",
                "예: work 09:00 18:30  또는  work 09:00 18:30 -30 pay 15000",
                null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 야간 처리
        if (end <= start) end = end.Add(TimeSpan.FromHours(24));

        var totalSpan   = end - start - TimeSpan.FromMinutes(lunch);
        var workedHours = totalSpan.TotalHours;
        if (workedHours < 0) workedHours = 0;

        _lastWorkedHours = workedHours;

        var wh      = (int)workedHours;
        var wm      = (int)Math.Round((workedHours - wh) * 60);
        var otHours = Math.Max(0, workedHours - 8.0);

        var summaryLine = $"근무 {workedHours:F1}시간 ({wh}시간 {wm}분)  초과 {otHours:F1}시간";
        items.Add(new LauncherItem(
            $"근무시간: {workedHours:F1}시간 ({wh}시간 {wm}분)",
            $"초과근무: {otHours:F1}시간  ·  Enter: 복사",
            null, ("copy", summaryLine), Symbol: "\uE916"));
        items.Add(new LauncherItem(
            $"초과근무: {otHours:F1}시간",
            $"기준 8시간 초과분  /  점심 제외: {lunch}분",
            null, ("copy", $"초과근무: {otHours:F1}시간"), Symbol: "\uE916"));

        if (pay > 0)
        {
            var (stdP, otP, totalP) = CalcPay(pay, workedHours);
            var payLine = $"급여: {totalP:#,0}원 (기본 {stdP:#,0}원 + 초과 {otP:#,0}원) | 시급 {pay:#,0}원";
            items.Add(new LauncherItem(
                $"급여: {totalP:#,0}원",
                $"기본 {stdP:#,0}원 + 초과(1.5배) {otP:#,0}원  ·  Enter: 복사",
                null, ("copy", payLine), Symbol: "\uE916"));
        }

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

    // ── ExecuteAsync ──────────────────────────────────────────────────────────

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("copy", string text))
        {
            try
            {
                Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
                NotificationService.Notify("근무시간", "클립보드에 복사했습니다.");
            }
            catch { }
        }
        return Task.CompletedTask;
    }
}
