using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace AxCopilot.Services;

/// <summary>
/// 에이전트 실행 통계를 로컬 JSON 파일에 기록/집계합니다.
/// %APPDATA%\AxCopilot\stats\agent_stats.json
/// </summary>
public static class AgentStatsService
{
    private static readonly string StatsDir = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "stats");

    private static readonly string StatsFile = Path.Combine(StatsDir, "agent_stats.json");

    private static readonly JsonSerializerOptions _jsonOpts = new()
    {
        WriteIndented = false,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    };

    // ─── 데이터 모델 ──────────────────────────────────────────────────────

    public record AgentSessionRecord
    {
        [JsonPropertyName("ts")]      public DateTime Timestamp   { get; init; } = DateTime.Now;
        [JsonPropertyName("tab")]     public string   Tab         { get; init; } = "";
        [JsonPropertyName("model")]   public string   Model       { get; init; } = "";
        [JsonPropertyName("calls")]   public int      ToolCalls   { get; init; }
        [JsonPropertyName("ok")]      public int      SuccessCount{ get; init; }
        [JsonPropertyName("fail")]    public int      FailCount   { get; init; }
        [JsonPropertyName("itok")]    public int      InputTokens { get; init; }
        [JsonPropertyName("otok")]    public int      OutputTokens{ get; init; }
        [JsonPropertyName("ms")]      public long     DurationMs  { get; init; }
        [JsonPropertyName("tools")]   public List<string> UsedTools { get; init; } = new();
    }

    /// <summary>집계 결과.</summary>
    public record AgentStatsSummary
    {
        public int    TotalSessions   { get; init; }
        public int    TotalToolCalls  { get; init; }
        public int    TotalTokens     { get; init; }
        public int    TotalInputTokens  { get; init; }
        public int    TotalOutputTokens { get; init; }
        public long   TotalDurationMs { get; init; }
        public Dictionary<string, int>  ToolFrequency   { get; init; } = new();
        public Dictionary<string, int>  ModelBreakdown  { get; init; } = new();
        public Dictionary<string, int>  TabBreakdown    { get; init; } = new();
        /// <summary>일별 세션 수 (날짜 키 "yyyy-MM-dd").</summary>
        public Dictionary<string, int>  DailySessions   { get; init; } = new();
        /// <summary>일별 토큰 수 (날짜 키 "yyyy-MM-dd").</summary>
        public Dictionary<string, int>  DailyTokens     { get; init; } = new();
    }

    // ─── 기록 ─────────────────────────────────────────────────────────────

    /// <summary>에이전트 세션 결과를 기록합니다. 비동기 fire-and-forget.</summary>
    public static void RecordSession(AgentSessionRecord record)
    {
        Task.Run(() =>
        {
            try
            {
                if (!Directory.Exists(StatsDir))
                    Directory.CreateDirectory(StatsDir);

                // 한 줄씩 append (JSONL 형식)
                var line = JsonSerializer.Serialize(record, _jsonOpts);
                File.AppendAllText(StatsFile, line + "\n");
            }
            catch (Exception ex)
            {
                LogService.Warn($"통계 기록 실패: {ex.Message}");
            }
        });
    }

    // ─── 집계 ─────────────────────────────────────────────────────────────

    /// <summary>지정 일수 이내의 통계를 집계합니다. days=0이면 전체.</summary>
    public static AgentStatsSummary Aggregate(int days = 0)
    {
        var records = LoadRecords(days);
        return BuildSummary(records);
    }

    /// <summary>통계 파일에서 레코드를 읽어옵니다.</summary>
    public static List<AgentSessionRecord> LoadRecords(int days = 0)
    {
        if (!File.Exists(StatsFile)) return new();

        var cutoff = days > 0 ? DateTime.Now.AddDays(-days) : DateTime.MinValue;
        var result = new List<AgentSessionRecord>();

        foreach (var line in File.ReadLines(StatsFile))
        {
            if (string.IsNullOrWhiteSpace(line)) continue;
            try
            {
                var rec = JsonSerializer.Deserialize<AgentSessionRecord>(line, _jsonOpts);
                if (rec != null && rec.Timestamp >= cutoff)
                    result.Add(rec);
            }
            catch (Exception) { /* 손상된 줄 건너뜀 */ }
        }

        return result;
    }

    private static AgentStatsSummary BuildSummary(List<AgentSessionRecord> records)
    {
        var toolFreq    = new Dictionary<string, int>();
        var modelBreak  = new Dictionary<string, int>();
        var tabBreak    = new Dictionary<string, int>();
        var dailySess   = new Dictionary<string, int>();
        var dailyTok    = new Dictionary<string, int>();

        int totalCalls  = 0, totalIn = 0, totalOut = 0;
        long totalMs    = 0;

        foreach (var r in records)
        {
            totalCalls += r.ToolCalls;
            totalIn    += r.InputTokens;
            totalOut   += r.OutputTokens;
            totalMs    += r.DurationMs;

            foreach (var t in r.UsedTools)
                toolFreq[t] = toolFreq.GetValueOrDefault(t) + 1;

            if (!string.IsNullOrEmpty(r.Model))
                modelBreak[r.Model] = modelBreak.GetValueOrDefault(r.Model) + 1;

            if (!string.IsNullOrEmpty(r.Tab))
                tabBreak[r.Tab] = tabBreak.GetValueOrDefault(r.Tab) + 1;

            var dateKey = r.Timestamp.ToString("yyyy-MM-dd");
            dailySess[dateKey]  = dailySess.GetValueOrDefault(dateKey) + 1;
            dailyTok[dateKey]   = dailyTok.GetValueOrDefault(dateKey)  + r.InputTokens + r.OutputTokens;
        }

        return new AgentStatsSummary
        {
            TotalSessions    = records.Count,
            TotalToolCalls   = totalCalls,
            TotalTokens      = totalIn + totalOut,
            TotalInputTokens = totalIn,
            TotalOutputTokens= totalOut,
            TotalDurationMs  = totalMs,
            ToolFrequency    = toolFreq.OrderByDescending(kv => kv.Value).Take(10)
                                       .ToDictionary(kv => kv.Key, kv => kv.Value),
            ModelBreakdown   = modelBreak,
            TabBreakdown     = tabBreak,
            DailySessions    = dailySess,
            DailyTokens      = dailyTok,
        };
    }

    /// <summary>통계 파일 크기 (bytes). 파일 없으면 0.</summary>
    public static long GetFileSize() =>
        File.Exists(StatsFile) ? new FileInfo(StatsFile).Length : 0;

    /// <summary>모든 통계 데이터를 삭제합니다.</summary>
    public static void Clear()
    {
        try { if (File.Exists(StatsFile)) File.Delete(StatsFile); }
        catch (Exception ex) { LogService.Warn($"통계 삭제 실패: {ex.Message}"); }
    }
}
