using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows.Media;
using AxCopilot.Models;
using AxCopilot.Views;
using AxCopilot.Services;

namespace AxCopilot.ViewModels;

/// <summary>하루 사용 통계를 막대 차트 아이템으로 표현</summary>
public class DayBarItem
{
    public string DateLabel   { get; init; } = ""; // "3/26" 형태
    public string DayLabel    { get; init; } = ""; // "월" 형태
    public int    Value       { get; init; }
    public double BarHeight   { get; init; }       // 0~66 (픽셀)
    public string ValueLabel  { get; init; } = "";
    public string ToolTipText { get; init; } = ""; // 마우스 호버 시 표시
    public bool   IsToday     { get; init; }
    public bool   HasData     => Value > 0;
}

/// <summary>인기 명령어 순위 아이템</summary>
public class CommandStatItem
{
    public int    Rank        { get; init; }
    public string Command     { get; init; } = "";
    public int    Count       { get; init; }
    public double BarWidth    { get; init; } // 0~200 (픽셀)
}

/// <summary>즐겨찾기 항목 (통계 화면에 표시)</summary>
public class FavoriteStatItem
{
    public int    Rank        { get; init; }
    public string Name        { get; init; } = "";
    public string Path        { get; init; } = "";
    public string Icon        { get; init; } = "\uE8B7"; // 기본: Folder
    public bool   Exists      { get; init; }
}

/// <summary>탭별 대화 비율 아이템</summary>
public class TabRatioItem
{
    public string TabName      { get; init; } = "";
    public int    Count        { get; init; }
    public double Percentage   { get; init; }   // 0~100
    public double BarWidth     { get; init; }   // 0~300 (픽셀)
    public string PercentLabel { get; init; } = "";
    public Brush  Color        { get; init; } = Brushes.MediumSlateBlue;
}

public class StatisticsViewModel : INotifyPropertyChanged
{
    private const double MaxBarHeight = 66.0;
    private const double MaxBarWidth  = 200.0;

    // ─── 차트 데이터 ─────────────────────────────────────────────────────────
    public ObservableCollection<DayBarItem>      LauncherOpenBars { get; } = new();
    public ObservableCollection<DayBarItem>      ActiveTimeBars   { get; } = new();
    public ObservableCollection<CommandStatItem> TopCommands      { get; } = new();
    public ObservableCollection<FavoriteStatItem> TopFavorites    { get; } = new();

    // AX Agent 통계
    public ObservableCollection<DayBarItem>      ChatCountBars    { get; } = new(); // 대화 빈도
    public ObservableCollection<DayBarItem>      TokenUsageBars   { get; } = new(); // 토큰 사용량

    // 추가 차트
    public ObservableCollection<DayBarItem>      WeekdayAvgBars   { get; } = new(); // 요일별 평균 호출
    public ObservableCollection<TabRatioItem>    TabChatRatios    { get; } = new(); // 탭별 대화 비율

    private bool _hasFavorites;
    public bool HasFavorites { get => _hasFavorites; private set { _hasFavorites = value; OnPropertyChanged(); } }

    // ─── 요약 카드 ───────────────────────────────────────────────────────────
    private string _todayDate         = "";
    private string _todaySummary      = "";
    private string _peakDate          = "";
    private string _peakDaySummary    = "";
    private string _weekSummary       = "";
    private string _totalOpensSummary = "";

    public string TodayDate         { get => _todayDate;          set { _todayDate = value;          OnPropertyChanged(); } }
    public string TodaySummary      { get => _todaySummary;       set { _todaySummary = value;       OnPropertyChanged(); } }
    public string PeakDate          { get => _peakDate;           set { _peakDate = value;           OnPropertyChanged(); } }
    public string PeakDaySummary    { get => _peakDaySummary;     set { _peakDaySummary = value;     OnPropertyChanged(); } }
    public string WeekSummary       { get => _weekSummary;        set { _weekSummary = value;        OnPropertyChanged(); } }
    public string TotalOpensSummary { get => _totalOpensSummary;  set { _totalOpensSummary = value;  OnPropertyChanged(); } }

    private string _agentSummary = "";
    public string AgentSummary { get => _agentSummary; set { _agentSummary = value; OnPropertyChanged(); } }

    // 토큰 비율
    private double _promptBarWidth;
    public double PromptBarWidth { get => _promptBarWidth; set { _promptBarWidth = value; OnPropertyChanged(); } }
    private double _completionBarWidth;
    public double CompletionBarWidth { get => _completionBarWidth; set { _completionBarWidth = value; OnPropertyChanged(); } }
    private string _promptTokenLabel = "";
    public string PromptTokenLabel { get => _promptTokenLabel; set { _promptTokenLabel = value; OnPropertyChanged(); } }
    private string _completionTokenLabel = "";
    public string CompletionTokenLabel { get => _completionTokenLabel; set { _completionTokenLabel = value; OnPropertyChanged(); } }
    private string _tokenRatioSummary = "";
    public string TokenRatioSummary { get => _tokenRatioSummary; set { _tokenRatioSummary = value; OnPropertyChanged(); } }

    public StatisticsViewModel()
    {
        Refresh();
    }

    public void Refresh()
    {
        var stats = UsageStatisticsService.GetStats(30);
        var today = DateTime.Today.ToString("yyyy-MM-dd");

        BuildLauncherOpenChart(stats, today);
        BuildActiveTimeChart(stats, today);
        BuildChatCountChart(stats, today);
        BuildTokenUsageChart(stats, today);
        BuildTopCommands(stats);
        BuildWeekdayAvgChart(stats);
        BuildTabChatRatios(stats);
        BuildTokenRatio(stats);
        BuildSummaryCards(stats, today);
        BuildTopFavorites();
    }

    // ─── 차트 빌더 ───────────────────────────────────────────────────────────

    private void BuildLauncherOpenChart(List<DailyUsageStats> stats, string today)
    {
        // 최근 14일만 표시
        var recent = stats.TakeLast(14).ToList();
        int maxVal = recent.Max(s => s.LauncherOpens);
        if (maxVal == 0) maxVal = 1;

        LauncherOpenBars.Clear();
        foreach (var s in recent)
        {
            var date = DateTime.TryParse(s.Date, out var d) ? d : DateTime.MinValue;
            LauncherOpenBars.Add(new DayBarItem
            {
                DateLabel   = date != DateTime.MinValue ? $"{date.Month}/{date.Day}" : "",
                DayLabel    = date != DateTime.MinValue ? GetKoreanDayOfWeek(date.DayOfWeek) : "",
                Value       = s.LauncherOpens,
                BarHeight   = MaxBarHeight * s.LauncherOpens / maxVal,
                ValueLabel  = s.LauncherOpens > 0 ? s.LauncherOpens.ToString() : "",
                ToolTipText = date != DateTime.MinValue
                    ? $"{date:yyyy-MM-dd} ({GetKoreanDayOfWeek(date.DayOfWeek)})\n호출 {s.LauncherOpens}회"
                    : "",
                IsToday     = s.Date == today
            });
        }
    }

    private void BuildActiveTimeChart(List<DailyUsageStats> stats, string today)
    {
        var recent = stats.TakeLast(14).ToList();
        int maxVal = recent.Max(s => s.ActiveSeconds);
        if (maxVal == 0) maxVal = 1;

        ActiveTimeBars.Clear();
        foreach (var s in recent)
        {
            var date = DateTime.TryParse(s.Date, out var d) ? d : DateTime.MinValue;
            ActiveTimeBars.Add(new DayBarItem
            {
                DateLabel   = date != DateTime.MinValue ? $"{date.Month}/{date.Day}" : "",
                DayLabel    = date != DateTime.MinValue ? GetKoreanDayOfWeek(date.DayOfWeek) : "",
                Value       = s.ActiveSeconds,
                BarHeight   = MaxBarHeight * s.ActiveSeconds / maxVal,
                ValueLabel  = FormatActiveTime(s.ActiveSeconds),
                ToolTipText = date != DateTime.MinValue
                    ? $"{date:yyyy-MM-dd} ({GetKoreanDayOfWeek(date.DayOfWeek)})\n활성 {FormatActiveTime(s.ActiveSeconds)}"
                    : "",
                IsToday     = s.Date == today
            });
        }
    }

    private void BuildChatCountChart(List<DailyUsageStats> stats, string today)
    {
        var recent = stats.TakeLast(14).ToList();
        // 탭별 합산
        int maxVal = recent.Max(s =>
        {
            int sum = 0;
            foreach (var kv in s.ChatCounts) sum += kv.Value;
            return sum;
        });
        if (maxVal == 0) maxVal = 1;

        ChatCountBars.Clear();
        foreach (var s in recent)
        {
            var dt = DateTime.TryParse(s.Date, out var d) ? d : DateTime.MinValue;
            int chat = s.ChatCounts.GetValueOrDefault("Chat");
            int cowork = s.ChatCounts.GetValueOrDefault("Cowork");
            int code = s.ChatCounts.GetValueOrDefault("Code");
            int total = chat + cowork + code;
            var isToday = s.Date == today;

            ChatCountBars.Add(new DayBarItem
            {
                DateLabel = dt.ToString("M/d"),
                DayLabel = dt.ToString("ddd")[..1],
                Value = total,
                BarHeight = total > 0 ? total * MaxBarHeight / maxVal : 2,
                ValueLabel = total > 0 ? total.ToString() : "",
                ToolTipText = $"{s.Date} ({dt:ddd})\nChat: {chat}회 · Cowork: {cowork}회 · Code: {code}회",
                IsToday = isToday,
            });
        }
    }

    private void BuildTokenUsageChart(List<DailyUsageStats> stats, string today)
    {
        var recent = stats.TakeLast(14).ToList();
        long maxVal = recent.Max(s => s.TotalTokens);
        if (maxVal == 0) maxVal = 1;

        TokenUsageBars.Clear();
        foreach (var s in recent)
        {
            var dt = DateTime.TryParse(s.Date, out var d) ? d : DateTime.MinValue;
            var isToday = s.Date == today;
            var tokens = s.TotalTokens;

            TokenUsageBars.Add(new DayBarItem
            {
                DateLabel = dt.ToString("M/d"),
                DayLabel = dt.ToString("ddd")[..1],
                Value = (int)Math.Min(tokens, int.MaxValue),
                BarHeight = tokens > 0 ? (double)tokens * MaxBarHeight / maxVal : 2,
                ValueLabel = tokens > 0 ? FormatTokens(tokens) : "",
                ToolTipText = $"{s.Date} ({dt:ddd})\n프롬프트: {s.PromptTokens:N0} · 완료: {s.CompletionTokens:N0} · 합계: {s.TotalTokens:N0}",
                IsToday = isToday,
            });
        }
    }

    private static string FormatTokens(long tokens) => tokens switch
    {
        >= 1_000_000 => $"{tokens / 1_000_000.0:F1}M",
        >= 1_000 => $"{tokens / 1_000.0:F1}K",
        _ => tokens.ToString(),
    };

    private void BuildWeekdayAvgChart(List<DailyUsageStats> stats)
    {
        // 요일별 평균 호출 (30일 데이터 → 요일 그룹)
        var groups = new Dictionary<DayOfWeek, List<int>>();
        foreach (DayOfWeek dow in Enum.GetValues<DayOfWeek>())
            groups[dow] = new();

        foreach (var s in stats)
        {
            if (DateTime.TryParse(s.Date, out var d))
                groups[d.DayOfWeek].Add(s.LauncherOpens);
        }

        // 월~일 순서
        var ordered = new[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday,
            DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday };
        double maxAvg = ordered.Max(dow => groups[dow].Count > 0 ? groups[dow].Average() : 0);
        if (maxAvg < 1) maxAvg = 1;

        WeekdayAvgBars.Clear();
        foreach (var dow in ordered)
        {
            var list = groups[dow];
            var avg = list.Count > 0 ? list.Average() : 0;
            WeekdayAvgBars.Add(new DayBarItem
            {
                DateLabel   = "",
                DayLabel    = GetKoreanDayOfWeek(dow),
                Value       = (int)Math.Round(avg),
                BarHeight   = avg > 0 ? avg * MaxBarHeight / maxAvg : 2,
                ValueLabel  = avg > 0 ? avg.ToString("F1") : "",
                ToolTipText = $"{GetKoreanDayOfWeek(dow)}요일 평균 {avg:F1}회 ({list.Count}일 데이터)",
                IsToday     = DateTime.Today.DayOfWeek == dow,
            });
        }
    }

    private void BuildTabChatRatios(List<DailyUsageStats> stats)
    {
        // 탭별 대화 비율 (30일 합계)
        int chat = 0, cowork = 0, code = 0;
        foreach (var s in stats)
        {
            chat   += s.ChatCounts.GetValueOrDefault("Chat");
            cowork += s.ChatCounts.GetValueOrDefault("Cowork");
            code   += s.ChatCounts.GetValueOrDefault("Code");
        }
        int total = chat + cowork + code;
        if (total == 0) total = 1;

        const double MaxWidth = 300.0;
        TabChatRatios.Clear();
        TabChatRatios.Add(new TabRatioItem
        {
            TabName = "Chat", Count = chat,
            Percentage = 100.0 * chat / total,
            BarWidth = MaxWidth * chat / total,
            PercentLabel = $"{100.0 * chat / total:F0}%  ({chat}회)",
            Color = ThemeResourceHelper.HexBrush("#818CF8")
        });
        TabChatRatios.Add(new TabRatioItem
        {
            TabName = "Cowork", Count = cowork,
            Percentage = 100.0 * cowork / total,
            BarWidth = MaxWidth * cowork / total,
            PercentLabel = $"{100.0 * cowork / total:F0}%  ({cowork}회)",
            Color = ThemeResourceHelper.HexBrush("#10B981")
        });
        TabChatRatios.Add(new TabRatioItem
        {
            TabName = "Code", Count = code,
            Percentage = 100.0 * code / total,
            BarWidth = MaxWidth * code / total,
            PercentLabel = $"{100.0 * code / total:F0}%  ({code}회)",
            Color = ThemeResourceHelper.HexBrush("#F59E0B")
        });
    }

    private void BuildTokenRatio(List<DailyUsageStats> stats)
    {
        long prompt = stats.Sum(s => s.PromptTokens);
        long completion = stats.Sum(s => s.CompletionTokens);
        long total = prompt + completion;
        if (total == 0) total = 1;

        const double TotalWidth = 400.0;
        PromptBarWidth = TotalWidth * prompt / total;
        CompletionBarWidth = TotalWidth * completion / total;
        PromptTokenLabel = $"입력 {FormatTokens(prompt)} ({100.0 * prompt / total:F0}%)";
        CompletionTokenLabel = $"출력 {FormatTokens(completion)} ({100.0 * completion / total:F0}%)";
        TokenRatioSummary = $"30일 합계  입력 {FormatTokens(prompt)} + 출력 {FormatTokens(completion)} = {FormatTokens(prompt + completion)}";
    }

    private void BuildTopCommands(List<DailyUsageStats> stats)
    {
        // 30일 집계
        var aggregate = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
        foreach (var s in stats)
            foreach (var (key, count) in s.CommandUsage)
            {
                aggregate.TryGetValue(key, out var cur);
                aggregate[key] = cur + count;
            }

        var top = aggregate
            .OrderByDescending(kv => kv.Value)
            .Take(10)
            .ToList();

        int maxCount = top.Count > 0 ? top[0].Value : 1;

        TopCommands.Clear();
        for (int i = 0; i < top.Count; i++)
        {
            TopCommands.Add(new CommandStatItem
            {
                Rank     = i + 1,
                Command  = top[i].Key,
                Count    = top[i].Value,
                BarWidth = MaxBarWidth * top[i].Value / maxCount
            });
        }
    }

    private void BuildSummaryCards(List<DailyUsageStats> stats, string today)
    {
        // 오늘 날짜 표시
        TodayDate = DateTime.Today.ToString("yyyy년 M월 d일");

        // 오늘 통계
        var todayStat = stats.FirstOrDefault(s => s.Date == today);
        TodaySummary = todayStat != null
            ? $"{todayStat.LauncherOpens}회 호출  ·  {FormatActiveTime(todayStat.ActiveSeconds)}"
            : "데이터 없음";

        // 역대 최고 호출일
        var peakDay = stats.OrderByDescending(s => s.LauncherOpens).FirstOrDefault();
        if (peakDay != null && peakDay.LauncherOpens > 0)
        {
            PeakDate = DateTime.TryParse(peakDay.Date, out var pd)
                ? pd.ToString("yyyy년 M월 d일")
                : peakDay.Date;
            PeakDaySummary = $"{peakDay.LauncherOpens}회 호출";
        }
        else
        {
            PeakDate = "";
            PeakDaySummary = "기록 없음";
        }

        // 이번 주 합계
        var weekStart = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
        var weekTotal = stats
            .Where(s => DateTime.TryParse(s.Date, out var d) && d >= weekStart)
            .Sum(s => s.LauncherOpens);
        WeekSummary = $"이번 주  {weekTotal}회";

        // 30일 총 호출
        var totalOpens = stats.Sum(s => s.LauncherOpens);
        TotalOpensSummary = $"30일 합계  {totalOpens}회";

        // AX Agent 요약
        var totalChats = stats.Sum(s => s.ChatCounts.Values.Sum());
        var totalTokens = stats.Sum(s => s.TotalTokens);
        var todayChats = todayStat?.ChatCounts.Values.Sum() ?? 0;
        var todayTokens = todayStat?.TotalTokens ?? 0;
        AgentSummary = $"오늘 {todayChats}회 대화 · {FormatTokens(todayTokens)} 토큰  |  30일 합계 {totalChats}회 · {FormatTokens(totalTokens)} 토큰";
    }

    private void BuildTopFavorites()
    {
        TopFavorites.Clear();
        var favFile = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "AxCopilot", "favorites.json");

        if (!File.Exists(favFile)) { HasFavorites = false; return; }

        try
        {
            var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
            var list = JsonSerializer.Deserialize<List<FavFileEntry>>(File.ReadAllText(favFile), opts) ?? new();

            var top = list.Take(6).ToList();
            if (top.Count == 0) { HasFavorites = false; return; }

            for (int i = 0; i < top.Count; i++)
            {
                var entry = top[i];
                var expanded = Environment.ExpandEnvironmentVariables(entry.Path);
                var isDir    = Directory.Exists(expanded);
                var exists   = isDir || File.Exists(expanded);
                TopFavorites.Add(new FavoriteStatItem
                {
                    Rank   = i + 1,
                    Name   = entry.Name,
                    Path   = entry.Path,
                    Icon   = isDir ? "\uE8B7" : "\uE8A5",  // Folder / Page
                    Exists = exists
                });
            }
            HasFavorites = TopFavorites.Count > 0;
        }
        catch (Exception) { HasFavorites = false; }
    }

    // favorites.json 역직렬화용 내부 레코드
    private class FavFileEntry
    {
        [JsonPropertyName("name")] public string Name { get; set; } = "";
        [JsonPropertyName("path")] public string Path { get; set; } = "";
    }

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

    private static string GetKoreanDayOfWeek(DayOfWeek dow) => dow switch
    {
        DayOfWeek.Monday    => "월",
        DayOfWeek.Tuesday   => "화",
        DayOfWeek.Wednesday => "수",
        DayOfWeek.Thursday  => "목",
        DayOfWeek.Friday    => "금",
        DayOfWeek.Saturday  => "토",
        _                   => "일"
    };

    private static string FormatActiveTime(int totalSeconds)
    {
        if (totalSeconds <= 0) return "";
        int h = totalSeconds / 3600;
        int m = (totalSeconds % 3600) / 60;
        if (h > 0 && m > 0) return $"{h}시간 {m}분";
        if (h > 0)           return $"{h}시간";
        if (m > 0)           return $"{m}분";
        return $"{totalSeconds}초";
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string? n = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
}
