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

namespace AxCopilot.Handlers;

/// <summary>
/// L16-3: 간단 할 일 목록 핸들러. "todo" 프리픽스로 사용합니다.
///
/// 예: todo                   → 전체 할 일 목록
///     todo 보고서 작성        → 새 항목 추가
///     todo done 1             → 1번 항목 완료 처리
///     todo del 1              → 1번 항목 삭제
///     todo clear              → 완료 항목 모두 삭제
///     todo clear all          → 전체 삭제
///     todo <검색어>           → 키워드 필터
/// Enter → 완료 토글 또는 항목 삭제.
/// 저장: %APPDATA%\AxCopilot\todos.json
/// </summary>
public class TodoHandler : IActionHandler
{
    public string? Prefix => "todo";

    public PluginMetadata Metadata => new(
        "Todo",
        "할 일 목록 — 추가 · 완료 · 삭제 · 검색",
        "1.0",
        "AX");

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

    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        WriteIndented = true,
        Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    };

    private record TodoItem(
        [property: JsonPropertyName("id")]   int    Id,
        [property: JsonPropertyName("text")] string Text,
        [property: JsonPropertyName("done")] bool   Done,
        [property: JsonPropertyName("at")]   string CreatedAt);

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

        if (string.IsNullOrWhiteSpace(q))
        {
            var pending   = todos.Count(t => !t.Done);
            var completed = todos.Count(t =>  t.Done);
            items.Add(new LauncherItem(
                $"할 일  {pending}개  완료 {completed}개",
                "todo <내용> → 추가  /  todo done <번호> → 완료  /  todo del <번호> → 삭제",
                null, null, Symbol: "\uE762"));

            if (todos.Count == 0)
            {
                items.Add(new LauncherItem("할 일이 없습니다", "todo <내용> 을 입력하면 추가됩니다",
                    null, null, Symbol: "\uE946"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }

            // 미완료 먼저, 완료 항목은 하단
            foreach (var t in todos.Where(t => !t.Done))
                items.Add(MakeTodoItem(t));

            if (completed > 0)
            {
                items.Add(new LauncherItem("── 완료됨 ──", $"{completed}개  /  todo clear → 정리",
                    null, ("clear_done", ""), Symbol: "\uE762"));
                foreach (var t in todos.Where(t => t.Done))
                    items.Add(MakeTodoItem(t));
            }

            items.Add(new LauncherItem("완료 항목 삭제", "todo clear — 완료 항목 정리",
                null, ("clear_done", ""), Symbol: "\uE762"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        // done / check / complete
        if (sub is "done" or "check" or "complete" or "✓")
        {
            var num = parts.Length > 1 && int.TryParse(parts[1].Trim(), out var n) ? n : -1;
            if (num < 0)
            {
                items.Add(new LauncherItem("번호를 입력하세요", "예: todo done 2", null, null, Symbol: "\uE783"));
            }
            else
            {
                var target = todos.FirstOrDefault(t => t.Id == num);
                if (target == null)
                    items.Add(new LauncherItem("없는 항목", $"#{num} 항목이 없습니다", null, null, Symbol: "\uE783"));
                else
                    items.Add(new LauncherItem(
                        target.Done ? $"#{num} 미완료로 되돌리기" : $"#{num} 완료 처리",
                        target.Text, null, ("toggle", num.ToString()), Symbol: "\uE762"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // del / delete / remove / rm
        if (sub is "del" or "delete" or "remove" or "rm")
        {
            var num = parts.Length > 1 && int.TryParse(parts[1].Trim(), out var n) ? n : -1;
            if (num < 0)
            {
                items.Add(new LauncherItem("번호를 입력하세요", "예: todo del 3", null, null, Symbol: "\uE783"));
            }
            else
            {
                var target = todos.FirstOrDefault(t => t.Id == num);
                if (target == null)
                    items.Add(new LauncherItem("없는 항목", $"#{num} 항목이 없습니다", null, null, Symbol: "\uE783"));
                else
                    items.Add(new LauncherItem($"#{num} 삭제",
                        target.Text, null, ("delete", num.ToString()), Symbol: "\uE762"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // clear — 완료 항목 삭제 / clear all → 전체 삭제
        if (sub == "clear")
        {
            var isAll = parts.Length > 1 && parts[1].ToLowerInvariant() == "all";
            if (isAll)
                items.Add(new LauncherItem("전체 삭제", $"할 일 {todos.Count}개 모두 삭제  · Enter 실행",
                    null, ("clear_all", ""), Symbol: "\uE762"));
            else
                items.Add(new LauncherItem("완료 항목 삭제",
                    $"완료 {todos.Count(t => t.Done)}개 삭제  · Enter 실행",
                    null, ("clear_done", ""), Symbol: "\uE762"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 숫자만 → 완료 토글 단축
        if (int.TryParse(q, out var idNum))
        {
            var target = todos.FirstOrDefault(t => t.Id == idNum);
            if (target != null)
            {
                items.Add(new LauncherItem(
                    target.Done ? $"#{idNum} 미완료로 되돌리기" : $"#{idNum} 완료 처리",
                    target.Text, null, ("toggle", idNum.ToString()), Symbol: "\uE762"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
        }

        // 검색 또는 새 항목 추가
        var filtered = todos.Where(t => t.Text.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
        if (filtered.Count > 0)
        {
            items.Add(new LauncherItem($"'{q}' 검색 결과  {filtered.Count}개", "", null, null, Symbol: "\uE762"));
            foreach (var t in filtered)
                items.Add(MakeTodoItem(t));
        }

        // 새 항목 추가 제안
        items.Add(new LauncherItem($"새 할 일 추가: {q}",
            "Enter → 목록에 추가",
            null, ("add", q), Symbol: "\uE710"));

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        var todos = LoadTodos();

        switch (item.Data)
        {
            case ("add", string text):
                var nextId = todos.Count > 0 ? todos.Max(t => t.Id) + 1 : 1;
                todos.Add(new TodoItem(nextId, text, false,
                    DateTime.Now.ToString("yyyy-MM-dd HH:mm")));
                SaveTodos(todos);
                NotificationService.Notify("Todo", $"추가됨: {text}");
                break;

            case ("toggle", string idStr) when int.TryParse(idStr, out var id):
                var idx = todos.FindIndex(t => t.Id == id);
                if (idx >= 0)
                {
                    todos[idx] = todos[idx] with { Done = !todos[idx].Done };
                    SaveTodos(todos);
                    var state = todos[idx].Done ? "완료" : "미완료";
                    NotificationService.Notify("Todo", $"#{id} {state}");
                }
                break;

            case ("delete", string idStr) when int.TryParse(idStr, out var id):
                var before = todos.Count;
                todos.RemoveAll(t => t.Id == id);
                if (todos.Count < before)
                {
                    SaveTodos(todos);
                    NotificationService.Notify("Todo", $"#{id} 삭제됨");
                }
                break;

            case ("clear_done", _):
                var doneCount = todos.RemoveAll(t => t.Done);
                SaveTodos(todos);
                NotificationService.Notify("Todo", $"완료 항목 {doneCount}개 삭제됨");
                break;

            case ("clear_all", _):
                SaveTodos(new List<TodoItem>());
                NotificationService.Notify("Todo", "전체 삭제됨");
                break;
        }
        return Task.CompletedTask;
    }

    // ── 저장/불러오기 ─────────────────────────────────────────────────────────

    private static List<TodoItem> LoadTodos()
    {
        try
        {
            if (!System.IO.File.Exists(DataPath)) return new List<TodoItem>();
            var json = System.IO.File.ReadAllText(DataPath, System.Text.Encoding.UTF8);
            return JsonSerializer.Deserialize<List<TodoItem>>(json, JsonOpts) ?? new List<TodoItem>();
        }
        catch { return new List<TodoItem>(); }
    }

    private static void SaveTodos(List<TodoItem> todos)
    {
        try
        {
            System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(DataPath)!);
            System.IO.File.WriteAllText(DataPath,
                JsonSerializer.Serialize(todos, JsonOpts),
                System.Text.Encoding.UTF8);
        }
        catch { /* 비핵심 */ }
    }

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

    private static LauncherItem MakeTodoItem(TodoItem t)
    {
        var icon     = t.Done ? "\uE73E" : "\uECC5";
        var prefix   = t.Done ? $"[✓] #{t.Id}" : $"[ ] #{t.Id}";
        var subtitle = $"{t.CreatedAt}  ·  done {t.Id} = 완료  /  del {t.Id} = 삭제";
        return new LauncherItem($"{prefix}  {t.Text}", subtitle,
            null, ("toggle", t.Id.ToString()), Symbol: icon);
    }
}
