using Microsoft.Win32;
using System.Windows.Threading;

namespace AxCopilot.Services;

/// <summary>
/// Windows 세션 잠금/해제를 감지하여 당일 근무 시간을 추적하고,
/// 설정된 간격마다 격려 팝업을 표시합니다.
///
/// 동작:
///  - 앱 시작 = 잠금 해제 상태로 간주, 첫 팝업 표시 후 주기 타이머 시작
///  - 잠금 → 현재 세션 시간을 당일 누계에 합산, 타이머 정지
///  - 잠금 해제 → 세션 시작 기록, 간격 조건 만족 시 팝업 표시, 타이머 재시작
///  - 자정을 넘기면 누계 및 마지막 표시 시각을 초기화
/// </summary>
public sealed class WorktimeReminderService : IDisposable
{
    private readonly SettingsService _settings;
    private readonly Dispatcher      _dispatcher;
    private readonly object          _lock = new();

    private DateTime _sessionStart;
    private TimeSpan _todayTotal;
    private DateTime _lastDate;
    private DateTime _lastShownAt;
    private System.Timers.Timer? _periodicTimer;
    private volatile bool _disposed;

    public WorktimeReminderService(SettingsService settings, Dispatcher dispatcher)
    {
        _settings     = settings;
        _dispatcher   = dispatcher;
        _sessionStart = DateTime.Now;
        _lastDate     = DateTime.Today;
        _lastShownAt  = DateTime.MinValue;

        // 이전 세션(재부팅/재시작 전)에서 기록된 당일 PC 사용시간을 복원
        try
        {
            var prevSeconds = UsageStatisticsService.GetTodayActiveSeconds();
            if (prevSeconds > 0)
            {
                _todayTotal = TimeSpan.FromSeconds(prevSeconds);
                LogService.Info($"이전 세션 누적 시간 복원: {_todayTotal}");
            }
        }
        catch (Exception ex)
        {
            LogService.Warn($"이전 세션 시간 복원 실패: {ex.Message}");
        }

        SystemEvents.SessionSwitch += OnSessionSwitch;
        LogService.Info("WorktimeReminderService 초기화 완료.");

        // 앱 시작 시에도 알림 조건 확인 (잠금 해제 상태에서 앱이 시작된 경우)
        var cfg = _settings.Settings.Reminder;
        if (cfg.Enabled)
        {
            // 약간의 지연 후 표시 (UI 초기화 완료 대기)
            _dispatcher.BeginInvoke(() =>
            {
                if (!_disposed) ShowPopup();
            }, DispatcherPriority.ApplicationIdle);

            StartPeriodicTimer();
        }
    }

    // ─── 세션 이벤트 ──────────────────────────────────────────────────────────

    private void OnSessionSwitch(object sender, SessionSwitchEventArgs e)
    {
        if (_disposed) return;

        LogService.Info($"SessionSwitch 이벤트: {e.Reason}");

        lock (_lock)
        {
            switch (e.Reason)
            {
                case SessionSwitchReason.SessionLock:
                    AccumulateSession();
                    StopPeriodicTimer();
                    LogService.Info($"세션 잠금. 누적 시간: {_todayTotal}");
                    break;

                case SessionSwitchReason.SessionUnlock:
                case SessionSwitchReason.SessionLogon:
                    ResetForNewDayIfNeeded();
                    _sessionStart = DateTime.Now;

                    var cfg = _settings.Settings.Reminder;
                    if (!cfg.Enabled)
                    {
                        LogService.Info("알림 비활성화 상태. 팝업 생략.");
                        break;
                    }

                    var interval = Math.Max(1, cfg.IntervalMinutes);
                    var elapsed = (DateTime.Now - _lastShownAt).TotalMinutes;
                    LogService.Info($"알림 간격 확인: 경과={elapsed:F1}분, 설정={interval}분");

                    if (elapsed >= interval)
                        ShowPopup();

                    StartPeriodicTimer();
                    break;
            }
        }
    }

    private void AccumulateSession()
    {
        // 호출부가 이미 lock 내부이므로 여기서 다시 lock하지 않음
        ResetForNewDayIfNeeded();
        _todayTotal  += DateTime.Now - _sessionStart;
        _sessionStart = DateTime.Now;
    }

    private void ResetForNewDayIfNeeded()
    {
        if (DateTime.Today == _lastDate) return;

        // 자정을 넘긴 경우: 세션 시작을 자정으로 리셋
        // (자정 이후 경과 시간만 오늘 누적에 반영되도록)
        var midnight = DateTime.Today;
        _sessionStart = midnight;
        _lastDate     = DateTime.Today;
        _lastShownAt  = DateTime.MinValue;

        // 새 날이면 통계 파일에서 기존 누적 로드 (자정 넘겨 앱이 계속 실행 중인 경우)
        try
        {
            var prevSeconds = UsageStatisticsService.GetTodayActiveSeconds();
            _todayTotal = prevSeconds > 0 ? TimeSpan.FromSeconds(prevSeconds) : TimeSpan.Zero;
        }
        catch (Exception)
        {
            _todayTotal = TimeSpan.Zero;
        }
    }

    // ─── 공개 API ─────────────────────────────────────────────────────────────

    /// <summary>당일 총 근무 시간(잠금 해제 누계 + 현재 세션)을 반환합니다.</summary>
    public TimeSpan GetTodayUsage()
    {
        lock (_lock)
        {
            ResetForNewDayIfNeeded();
            return _todayTotal + (DateTime.Now - _sessionStart);
        }
    }

    // ─── 주기 타이머 ─────────────────────────────────────────────────────────

    private void StartPeriodicTimer()
    {
        StopPeriodicTimer();
        var intervalMin = Math.Max(1, _settings.Settings.Reminder.IntervalMinutes);
        _periodicTimer = new System.Timers.Timer(intervalMin * 60_000);
        _periodicTimer.Elapsed += OnPeriodicTimerElapsed;
        _periodicTimer.AutoReset = true;
        _periodicTimer.Start();
        LogService.Info($"격려 알림 주기 타이머 시작: {intervalMin}분 간격");
    }

    private void StopPeriodicTimer()
    {
        if (_periodicTimer != null)
        {
            _periodicTimer.Elapsed -= OnPeriodicTimerElapsed;
            _periodicTimer.Stop();
            _periodicTimer.Dispose();
            _periodicTimer = null;
        }
    }

    private void OnPeriodicTimerElapsed(object? sender, System.Timers.ElapsedEventArgs e)
    {
        if (_disposed) return;

        var cfg = _settings.Settings.Reminder;
        if (!cfg.Enabled)
        {
            StopPeriodicTimer();
            return;
        }

        lock (_lock)
        {
            ResetForNewDayIfNeeded();
            ShowPopup();
        }
    }

    /// <summary>설정 변경 시 외부에서 타이머를 재시작합니다.</summary>
    public void RestartTimer()
    {
        var cfg = _settings.Settings.Reminder;
        if (cfg.Enabled)
            StartPeriodicTimer();
        else
            StopPeriodicTimer();
    }

    // ─── 팝업 표시 ────────────────────────────────────────────────────────────

    private void ShowPopup()
    {
        _lastShownAt = DateTime.Now;
        var usage = GetTodayUsage();
        var (text, author) = QuoteService.GetRandom(_settings?.Settings.Reminder.EnabledCategories);

        _dispatcher.BeginInvoke(() =>
        {
            if (_disposed) return;
            try
            {
                if (_settings == null) return;
                var popup = new AxCopilot.Views.ReminderPopupWindow(
                    text, author, usage, _settings);
                popup.Show();
            }
            catch (Exception ex)
            {
                LogService.Warn($"알림 팝업 표시 실패: {ex.Message}");
            }
        }, DispatcherPriority.Normal);
    }

    // ─── Dispose ──────────────────────────────────────────────────────────────

    public void Dispose()
    {
        if (_disposed) return;
        _disposed = true;
        StopPeriodicTimer();
        SystemEvents.SessionSwitch -= OnSessionSwitch;
    }
}
