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

namespace AxCopilot.Handlers;

/// <summary>
/// L25-4: 오늘 업무 통합 뷰. "today" 프리픽스로 사용합니다.
///
/// 예: today                  → 오늘 날짜/요일/공휴일 + 할일 + 알림 + 공휴일 현황
/// </summary>
public class TodayHandler : IActionHandler
{
    public string? Prefix => "today";

    public PluginMetadata Metadata => new(
        "오늘",
        "오늘 업무 통합 뷰 — 날짜·할일·알림·공휴일",
        "1.0",
        "AX");

    private static readonly string TodoPath = System.IO.Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "todos.json");

    private static readonly string[] DayNames = ["일", "월", "화", "수", "목", "금", "토"];

    // 2025~2027 주요 공휴일 (CalHandler에 직접 접근 불가하므로 독립 정의)
    private static readonly Dictionary<DateOnly, string> Holidays = new()
    {
        // 2025
        { new DateOnly(2025,  1,  1), "신정" },
        { new DateOnly(2025,  1, 28), "설날연휴" },
        { new DateOnly(2025,  1, 29), "설날" },
        { new DateOnly(2025,  1, 30), "설날연휴" },
        { new DateOnly(2025,  3,  1), "삼일절" },
        { new DateOnly(2025,  3,  3), "대체공휴일" },
        { new DateOnly(2025,  5,  5), "어린이날" },
        { new DateOnly(2025,  5,  6), "부처님오신날" },
        { new DateOnly(2025,  6,  6), "현충일" },
        { new DateOnly(2025,  8, 15), "광복절" },
        { new DateOnly(2025, 10,  3), "개천절" },
        { new DateOnly(2025, 10,  5), "추석연휴" },
        { new DateOnly(2025, 10,  6), "추석" },
        { new DateOnly(2025, 10,  7), "추석연휴" },
        { new DateOnly(2025, 10,  8), "대체공휴일" },
        { new DateOnly(2025, 10,  9), "한글날" },
        { new DateOnly(2025, 12, 25), "크리스마스" },

        // 2026
        { new DateOnly(2026,  1,  1), "신정" },
        { new DateOnly(2026,  2, 17), "설날연휴" },
        { new DateOnly(2026,  2, 18), "설날" },
        { new DateOnly(2026,  2, 19), "설날연휴" },
        { new DateOnly(2026,  3,  1), "삼일절" },
        { new DateOnly(2026,  3,  2), "대체공휴일" },
        { new DateOnly(2026,  5,  5), "어린이날" },
        { new DateOnly(2026,  5, 24), "부처님오신날" },
        { new DateOnly(2026,  5, 25), "대체공휴일" },
        { new DateOnly(2026,  6,  6), "현충일" },
        { new DateOnly(2026,  6,  8), "대체공휴일" },
        { new DateOnly(2026,  8, 15), "광복절" },
        { new DateOnly(2026,  8, 17), "대체공휴일" },
        { new DateOnly(2026,  9, 24), "추석연휴" },
        { new DateOnly(2026,  9, 25), "추석" },
        { new DateOnly(2026,  9, 26), "추석연휴" },
        { new DateOnly(2026, 10,  3), "개천절" },
        { new DateOnly(2026, 10,  5), "대체공휴일" },
        { new DateOnly(2026, 10,  9), "한글날" },
        { new DateOnly(2026, 12, 25), "크리스마스" },

        // 2027
        { new DateOnly(2027,  1,  1), "신정" },
        { new DateOnly(2027,  2,  7), "설날연휴" },
        { new DateOnly(2027,  2,  8), "설날" },
        { new DateOnly(2027,  2,  9), "설날연휴" },
        { new DateOnly(2027,  3,  1), "삼일절" },
        { new DateOnly(2027,  5,  5), "어린이날" },
        { new DateOnly(2027,  5, 13), "부처님오신날" },
        { new DateOnly(2027,  6,  6), "현충일" },
        { new DateOnly(2027,  6,  7), "대체공휴일" },
        { new DateOnly(2027,  8, 15), "광복절" },
        { new DateOnly(2027,  8, 16), "대체공휴일" },
        { new DateOnly(2027,  9, 13), "추석연휴" },
        { new DateOnly(2027,  9, 14), "추석" },
        { new DateOnly(2027,  9, 15), "추석연휴" },
        { new DateOnly(2027, 10,  3), "개천절" },
        { new DateOnly(2027, 10,  4), "대체공휴일" },
        { new DateOnly(2027, 10,  9), "한글날" },
        { new DateOnly(2027, 12, 25), "크리스마스" },
        { new DateOnly(2027, 12, 27), "대체공휴일" },
    };

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var items = new List<LauncherItem>();
        var today = DateOnly.FromDateTime(DateTime.Today);
        var now   = DateTime.Now;

        // ─── 항목1: 날짜 헤더 ────────────────────────────────────────────────
        var dow     = DayNames[(int)today.DayOfWeek];
        var isHol   = Holidays.TryGetValue(today, out var holName);
        var isWknd  = today.DayOfWeek == DayOfWeek.Saturday || today.DayOfWeek == DayOfWeek.Sunday;
        string status;
        if (isHol)       status = $"공휴일 — {holName}";
        else if (isWknd) status = "주말";
        else             status = "평일 (업무일)";

        items.Add(new LauncherItem(
            $"{today:yyyy년 MM월 dd일} ({dow}요일)",
            status,
            null, ("copy", $"{today:yyyy-MM-dd} ({dow}) {status}"),
            Symbol: "\uE8BF"));

        // ─── 항목2: 할일 ─────────────────────────────────────────────────────
        var (pendingCount, recentTitles) = LoadPendingTodos();
        var todoSub = pendingCount == 0
            ? "미완료 할일 없음"
            : string.Join("  /  ", recentTitles.Take(3));
        items.Add(new LauncherItem(
            $"미완료 할일  {pendingCount}건",
            todoSub,
            null, null, Symbol: "\uE762"));

        // ─── 항목3: 알림 ─────────────────────────────────────────────────────
        var todayReminders = RemindHandler.GetTodayReminders();
        if (todayReminders.Count == 0)
        {
            items.Add(new LauncherItem("오늘 알림 없음",
                "remind HH:mm 메시지  로 알림을 설정하세요",
                null, null, Symbol: "\uE787"));
        }
        else
        {
            var remindSub = string.Join("  /  ",
                todayReminders.Take(3).Select(r => $"{r.Time:HH:mm} {r.Message}"));
            items.Add(new LauncherItem(
                $"오늘 알림  {todayReminders.Count}건",
                remindSub,
                null, null, Symbol: "\uE787"));
        }

        // ─── 항목4: 다음 공휴일 ──────────────────────────────────────────────
        var nextHol = Holidays.Keys
            .Where(d => d > today)
            .OrderBy(d => d)
            .FirstOrDefault();

        if (nextHol != default)
        {
            var diff    = nextHol.DayNumber - today.DayNumber;
            var nextDow = DayNames[(int)nextHol.DayOfWeek];
            items.Add(new LauncherItem(
                $"다음 공휴일: {nextHol:MM/dd} ({nextDow})  {Holidays[nextHol]}",
                $"D-{diff}일",
                null, ("copy", $"{nextHol:yyyy-MM-dd} {Holidays[nextHol]} D-{diff}"),
                Symbol: "\uE787"));
        }
        else
        {
            items.Add(new LauncherItem("다음 공휴일 정보 없음", "",
                null, null, Symbol: "\uE787"));
        }

        // ─── 항목5: 이번달 잔여 업무일 ───────────────────────────────────────
        var lastDay   = new DateOnly(today.Year, today.Month,
            DateTime.DaysInMonth(today.Year, today.Month));
        var remaining = CountWorkdaysFrom(today, lastDay);
        var total     = CountWorkdays(today.Year, today.Month);
        items.Add(new LauncherItem(
            $"이번달 잔여 업무일  {remaining}일",
            $"{today.Year}년 {today.Month}월 총 업무일: {total}일",
            null, null, Symbol: "\uE8BF"));

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

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

    // ── 할일 파싱 ────────────────────────────────────────────────────────────

    private static (int pending, List<string> titles) LoadPendingTodos()
    {
        try
        {
            if (!System.IO.File.Exists(TodoPath)) return (0, []);
            var json = System.IO.File.ReadAllText(TodoPath, System.Text.Encoding.UTF8);
            using var doc = JsonDocument.Parse(json);
            var root    = doc.RootElement;
            if (root.ValueKind != JsonValueKind.Array) return (0, []);

            var pending = 0;
            var titles  = new List<string>();
            foreach (var el in root.EnumerateArray())
            {
                var done = false;
                if (el.TryGetProperty("done", out var doneProp))
                    done = doneProp.GetBoolean();
                if (done) continue;

                pending++;
                if (titles.Count < 3 && el.TryGetProperty("text", out var textProp))
                    titles.Add(textProp.GetString() ?? "");
            }
            return (pending, titles);
        }
        catch { return (0, []); }
    }

    // ── 업무일 계산 ──────────────────────────────────────────────────────────

    private static bool IsHoliday(DateOnly d) =>
        Holidays.ContainsKey(d) ||
        d.DayOfWeek == DayOfWeek.Saturday ||
        d.DayOfWeek == DayOfWeek.Sunday;

    private static int CountWorkdays(int year, int month)
    {
        var days  = DateTime.DaysInMonth(year, month);
        var count = 0;
        for (var i = 1; i <= days; i++)
            if (!IsHoliday(new DateOnly(year, month, i))) count++;
        return count;
    }

    private static int CountWorkdaysFrom(DateOnly from, DateOnly to)
    {
        var count = 0;
        var cur   = from;
        while (cur <= to)
        {
            if (!IsHoliday(cur)) count++;
            cur = cur.AddDays(1);
        }
        return count;
    }
}
