using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L19-2: 타이머·알람 핸들러. "timer" 프리픽스로 사용합니다.
///
/// 예: timer                  → 사용법 + 실행 중인 타이머 목록
///     timer 30               → 30초 타이머 (Enter로 시작)
///     timer 5m               → 5분 타이머
///     timer 1h30m            → 1시간 30분 타이머
///     timer 2h               → 2시간 타이머
///     timer 10m30s           → 10분 30초 타이머
///     timer stop             → 모든 타이머 취소
///     timer stop <id>        → 특정 타이머 취소
/// Enter → 타이머 시작 (또는 중단).
/// </summary>
public class TimerHandler : IActionHandler
{
    public string? Prefix => "timer";

    public PluginMetadata Metadata => new(
        "Timer",
        "타이머·알람 — 초/분/시간 단위 백그라운드 타이머",
        "1.0",
        "AX");

    // 타이머 레코드
    private record TimerEntry(int Id, string Label, TimeSpan Duration, DateTime StartAt, CancellationTokenSource Cts);

    // 정적 타이머 레지스트리
    private static readonly List<TimerEntry>      _timers  = [];
    private static readonly object                 _lock    = new();
    private static int                             _nextId  = 1;

    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("타이머·알람",
                "timer 30  /  timer 5m  /  timer 1h30m  /  timer stop",
                null, null, Symbol: "\uE916"));
            items.Add(new LauncherItem("사용법", "timer <시간>  · 예: 30(초) / 5m / 1h30m / 2h", null, null, Symbol: "\uE916"));
            AddRunningTimers(items);
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        // stop 명령
        if (sub is "stop" or "cancel" or "취소")
        {
            lock (_lock)
            {
                if (_timers.Count == 0)
                {
                    items.Add(new LauncherItem("실행 중인 타이머 없음", "취소할 타이머가 없습니다",
                        null, null, Symbol: "\uE916"));
                    return Task.FromResult<IEnumerable<LauncherItem>>(items);
                }

                // 특정 ID 취소
                if (parts.Length >= 2 && int.TryParse(parts[1], out var stopId))
                {
                    var t = _timers.FirstOrDefault(x => x.Id == stopId);
                    if (t != null)
                        items.Add(new LauncherItem($"타이머 #{t.Id} '{t.Label}' 취소",
                            $"Enter로 취소합니다", null, ("stop", stopId.ToString()), Symbol: "\uE916"));
                    else
                        items.Add(new LauncherItem($"타이머 #{stopId}를 찾을 수 없습니다",
                            "timer 명령으로 목록을 확인하세요", null, null, Symbol: "\uE783"));
                    return Task.FromResult<IEnumerable<LauncherItem>>(items);
                }

                // 전체 취소
                items.Add(new LauncherItem($"모든 타이머 취소 ({_timers.Count}개)",
                    "Enter로 모두 취소합니다", null, ("stop_all", ""), Symbol: "\uE916"));
                foreach (var t in _timers)
                    items.Add(new LauncherItem($"  #{t.Id} {t.Label}",
                        $"시작: {t.StartAt:HH:mm:ss}  남은: {Remaining(t)}",
                        null, ("stop", t.Id.ToString()), Symbol: "\uE916"));
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 시간 파싱 시도
        if (TryParseTime(sub, out var duration) && duration > TimeSpan.Zero)
        {
            var label   = FormatDuration(duration);
            var endTime = DateTime.Now.Add(duration);
            items.Add(new LauncherItem($"⏱ {label} 타이머 시작",
                $"완료: {endTime:HH:mm:ss}  · Enter로 시작",
                null, ("start", DurationToSeconds(duration).ToString()), Symbol: "\uE916"));
            items.Add(new LauncherItem($"완료 예정", $"{endTime:HH:mm:ss}", null, null, Symbol: "\uE916"));
            items.Add(new LauncherItem($"경과 시간", label, null, null, Symbol: "\uE916"));

            // 실행 중 타이머 표시
            AddRunningTimers(items);
        }
        else
        {
            items.Add(new LauncherItem($"형식 오류: '{q}'",
                "예: timer 30  /  timer 5m  /  timer 1h30m  /  timer stop",
                null, null, Symbol: "\uE783"));
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("start", string secStr) when long.TryParse(secStr, out var sec):
            {
                var duration = TimeSpan.FromSeconds(sec);
                var label    = FormatDuration(duration);
                var cts      = new CancellationTokenSource();
                int id;
                lock (_lock)
                {
                    id = _nextId++;
                    _timers.Add(new TimerEntry(id, label, duration, DateTime.Now, cts));
                }
                NotificationService.Notify("Timer", $"⏱ #{id} {label} 타이머 시작됩니다.");
                _ = RunTimerAsync(id, label, duration, cts.Token);
                break;
            }

            case ("stop", string idStr) when int.TryParse(idStr, out var stopId):
            {
                TimerEntry? entry = null;
                lock (_lock)
                {
                    entry = _timers.FirstOrDefault(t => t.Id == stopId);
                    if (entry != null) _timers.Remove(entry);
                }
                if (entry != null)
                {
                    entry.Cts.Cancel();
                    NotificationService.Notify("Timer", $"⏹ #{entry.Id} '{entry.Label}' 타이머가 취소되었습니다.");
                }
                break;
            }

            case ("stop_all", _):
            {
                List<TimerEntry> all;
                lock (_lock)
                {
                    all = [.._timers];
                    _timers.Clear();
                }
                foreach (var t in all) t.Cts.Cancel();
                NotificationService.Notify("Timer", $"⏹ 타이머 {all.Count}개 모두 취소됐습니다.");
                break;
            }
        }
        return Task.CompletedTask;
    }

    // ── 타이머 실행 ──────────────────────────────────────────────────────────

    private static async Task RunTimerAsync(int id, string label, TimeSpan duration, CancellationToken token)
    {
        try
        {
            await Task.Delay(duration, token);
            // 완료 — 레지스트리에서 제거
            lock (_lock) { _timers.RemoveAll(t => t.Id == id); }
            NotificationService.Notify("⏰ 타이머 완료", $"#{id} {label} 타이머가 종료되었습니다!");
        }
        catch (OperationCanceledException)
        {
            // 취소됨 — 이미 처리됨
        }
    }

    // ── 파싱 헬퍼 ────────────────────────────────────────────────────────────

    private static bool TryParseTime(string s, out TimeSpan ts)
    {
        ts = TimeSpan.Zero;
        s  = s.ToLowerInvariant().Trim();

        // 숫자만 → 초
        if (long.TryParse(s, out var sec))
        {
            ts = TimeSpan.FromSeconds(sec);
            return true;
        }

        // 복합 형식: 1h30m20s
        long hours = 0, minutes = 0, seconds = 0;
        var  rem   = s;
        bool found = false;

        if (TryExtractUnit(ref rem, 'h', out var h)) { hours   = h; found = true; }
        if (TryExtractUnit(ref rem, 'm', out var m)) { minutes = m; found = true; }
        if (TryExtractUnit(ref rem, 's', out var sv)){ seconds = sv; found = true; }

        if (found && rem.Length == 0)
        {
            ts = TimeSpan.FromSeconds(hours * 3600 + minutes * 60 + seconds);
            return true;
        }

        return false;
    }

    private static bool TryExtractUnit(ref string s, char unit, out long value)
    {
        value = 0;
        var idx = s.IndexOf(unit);
        if (idx <= 0) return false;
        var numStr = s[..idx];
        if (!long.TryParse(numStr, out value)) return false;
        s = s[(idx + 1)..];
        return true;
    }

    private static string FormatDuration(TimeSpan ts)
    {
        if (ts.TotalSeconds < 60)     return $"{(long)ts.TotalSeconds}초";
        if (ts.TotalMinutes < 60)
        {
            var mins = (long)ts.TotalMinutes;
            var secs = (long)(ts.TotalSeconds - mins * 60);
            return secs > 0 ? $"{mins}분 {secs}초" : $"{mins}분";
        }
        var h = (long)ts.TotalHours;
        var m = (long)(ts.TotalMinutes - h * 60);
        var s = (long)(ts.TotalSeconds - h * 3600 - m * 60);
        var result = $"{h}시간";
        if (m > 0) result += $" {m}분";
        if (s > 0) result += $" {s}초";
        return result;
    }

    private static long DurationToSeconds(TimeSpan ts) => (long)ts.TotalSeconds;

    private static string Remaining(TimerEntry t)
    {
        var elapsed = DateTime.Now - t.StartAt;
        var left    = t.Duration - elapsed;
        if (left <= TimeSpan.Zero) return "완료";
        return FormatDuration(left);
    }

    private static void AddRunningTimers(List<LauncherItem> items)
    {
        List<TimerEntry> running;
        lock (_lock) { running = [.._timers]; }
        if (running.Count == 0) return;

        items.Add(new LauncherItem($"── 실행 중인 타이머 {running.Count}개 ──", "", null, null, Symbol: "\uE916"));
        foreach (var t in running)
        {
            var left = Remaining(t);
            items.Add(new LauncherItem($"#{t.Id}  {t.Label}", $"남은 시간: {left}  · 시작: {t.StartAt:HH:mm:ss}",
                null, ("stop", t.Id.ToString()), Symbol: "\uE916"));
        }
    }
}
