using System.IO;
using System.Text.Json;
using AxCopilot.Models;

namespace AxCopilot.Services;

/// <summary>
/// 일별 사용 통계를 기록하고 조회합니다.
/// 저장 위치: %APPDATA%\AxCopilot\stats\YYYY-MM-DD.json
/// 30일 초과 파일은 자동 삭제(롤링).
/// </summary>
internal static class UsageStatisticsService
{
    private static readonly string _statsDir = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "stats");

    private static DailyUsageStats _today = new();
    private static bool _initialized;
    private static readonly object _lock = new();
    private const int RetentionDays = 30;

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

    public static void RecordLauncherOpen()
    {
        EnsureInitialized();
        lock (_lock) { _today.LauncherOpens++; }
        _ = SaveTodayAsync();
    }

    public static void RecordCommandUsage(string commandKey)
    {
        if (string.IsNullOrWhiteSpace(commandKey)) return;
        EnsureInitialized();
        lock (_lock)
        {
            _today.CommandUsage.TryGetValue(commandKey, out var cur);
            _today.CommandUsage[commandKey] = cur + 1;
        }
        _ = SaveTodayAsync();
    }

    public static void AddActiveSeconds(int seconds)
    {
        if (seconds <= 0) return;
        EnsureInitialized();
        lock (_lock) { _today.ActiveSeconds += seconds; }
        _ = SaveTodayAsync();
    }

    /// <summary>당일 기록된 PC 활성 시간(초)을 반환합니다. 재시작 전 누적분 포함.</summary>
    public static int GetTodayActiveSeconds()
    {
        EnsureInitialized();
        lock (_lock) { return _today.ActiveSeconds; }
    }

    /// <summary>AX Agent 대화를 탭별로 기록합니다.</summary>
    public static void RecordChat(string tab)
    {
        if (string.IsNullOrWhiteSpace(tab)) tab = "Chat";
        EnsureInitialized();
        lock (_lock)
        {
            _today.ChatCounts.TryGetValue(tab, out var cur);
            _today.ChatCounts[tab] = cur + 1;
        }
        _ = SaveTodayAsync();
    }

    /// <summary>토큰 사용량을 기록합니다.</summary>
    public static void RecordTokens(int promptTokens, int completionTokens)
    {
        if (promptTokens <= 0 && completionTokens <= 0) return;
        EnsureInitialized();
        lock (_lock)
        {
            _today.PromptTokens += promptTokens;
            _today.CompletionTokens += completionTokens;
            _today.TotalTokens += promptTokens + completionTokens;
        }
        _ = SaveTodayAsync();
    }

    /// <summary>최근 <paramref name="days"/>일치 통계를 날짜 오름차순으로 반환합니다.</summary>
    public static List<DailyUsageStats> GetStats(int days = 30)
    {
        EnsureInitialized();
        var result = new List<DailyUsageStats>();
        var today  = DateTime.Today;

        for (int i = days - 1; i >= 0; i--)
        {
            var date    = today.AddDays(-i);
            var dateStr = date.ToString("yyyy-MM-dd");

            if (dateStr == _today.Date)
            {
                DailyUsageStats snapshot;
                lock (_lock) { snapshot = CloneToday(); }
                result.Add(snapshot);
                continue;
            }

            var path = GetFilePath(dateStr);
            if (File.Exists(path))
            {
                try
                {
                    var json = File.ReadAllText(path);
                    var stat = JsonSerializer.Deserialize<DailyUsageStats>(json);
                    if (stat != null) result.Add(stat);
                    else result.Add(new DailyUsageStats { Date = dateStr });
                }
                catch (Exception) { result.Add(new DailyUsageStats { Date = dateStr }); }
            }
            else
            {
                result.Add(new DailyUsageStats { Date = dateStr });
            }
        }

        return result;
    }

    // ─── 내부 ────────────────────────────────────────────────────────────────

    private static void EnsureInitialized()
    {
        if (_initialized) return;
        lock (_lock)
        {
            if (_initialized) return;
            try
            {
                Directory.CreateDirectory(_statsDir);
                var todayStr = DateTime.Today.ToString("yyyy-MM-dd");
                var path     = GetFilePath(todayStr);

                if (File.Exists(path))
                {
                    var json = File.ReadAllText(path);
                    var stat = JsonSerializer.Deserialize<DailyUsageStats>(json);
                    _today = stat ?? new DailyUsageStats { Date = todayStr };
                }
                else
                {
                    _today = new DailyUsageStats { Date = todayStr };
                }

                PurgeOldFiles();
            }
            catch (Exception ex)
            {
                LogService.Warn($"통계 서비스 초기화 실패: {ex.Message}");
                _today = new DailyUsageStats { Date = DateTime.Today.ToString("yyyy-MM-dd") };
            }
            _initialized = true;
        }
    }

    private static void PurgeOldFiles()
    {
        try
        {
            var cutoff = DateTime.Today.AddDays(-RetentionDays);
            foreach (var file in Directory.GetFiles(_statsDir, "????-??-??.json"))
            {
                var name = Path.GetFileNameWithoutExtension(file);
                if (DateTime.TryParse(name, out var fileDate) && fileDate < cutoff)
                    File.Delete(file);
            }
        }
        catch (Exception ex)
        {
            LogService.Warn($"통계 파일 정리 실패: {ex.Message}");
        }
    }

    private static async Task SaveTodayAsync()
    {
        try
        {
            DailyUsageStats snapshot;
            lock (_lock) { snapshot = CloneToday(); }

            var path = GetFilePath(snapshot.Date);
            var json = JsonSerializer.Serialize(snapshot, new JsonSerializerOptions { WriteIndented = false });
            await File.WriteAllTextAsync(path, json);
        }
        catch (Exception ex)
        {
            LogService.Warn($"통계 저장 실패: {ex.Message}");
        }
    }

    private static DailyUsageStats CloneToday() => new()
    {
        Date             = _today.Date,
        LauncherOpens    = _today.LauncherOpens,
        ActiveSeconds    = _today.ActiveSeconds,
        CommandUsage     = new Dictionary<string, int>(_today.CommandUsage),
        ChatCounts       = new Dictionary<string, int>(_today.ChatCounts),
        TotalTokens      = _today.TotalTokens,
        PromptTokens     = _today.PromptTokens,
        CompletionTokens = _today.CompletionTokens,
    };

    private static string GetFilePath(string dateStr)
        => Path.Combine(_statsDir, $"{dateStr}.json");
}
