using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System.Globalization;
using Volo.Abp.Application.Services;
using Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
using Yi.Framework.AiHub.Application.Contracts.IServices;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Chat;
using Yi.Framework.AiHub.Domain.Entities.Model;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace Yi.Framework.AiHub.Application.Services;

/// <summary>
/// 系统使用量统计服务实现
/// </summary>
[Authorize(Roles = "admin")]
public class SystemUsageStatisticsService : ApplicationService, ISystemUsageStatisticsService
{
    private readonly ISqlSugarRepository<PremiumPackageAggregateRoot> _premiumPackageRepository;
    private readonly ISqlSugarRepository<AiRechargeAggregateRoot> _rechargeRepository;
    private readonly ISqlSugarRepository<MessageAggregateRoot> _messageRepository;
    private readonly ISqlSugarRepository<AiModelEntity, Guid> _modelRepository;

    public SystemUsageStatisticsService(
        ISqlSugarRepository<PremiumPackageAggregateRoot> premiumPackageRepository,
        ISqlSugarRepository<AiRechargeAggregateRoot> rechargeRepository,
        ISqlSugarRepository<MessageAggregateRoot> messageRepository,
        ISqlSugarRepository<AiModelEntity, Guid> modelRepository)
    {
        _premiumPackageRepository = premiumPackageRepository;
        _rechargeRepository = rechargeRepository;
        _messageRepository = messageRepository;
        _modelRepository = modelRepository;
    }

    /// <summary>
    /// 获取利润统计数据
    /// </summary>
    [HttpPost("system-statistics/profit")]
    public async Task<ProfitStatisticsOutput> GetProfitStatisticsAsync(ProfitStatisticsInput input)
    {
        // 1. 获取尊享包总消耗和剩余库存
        var premiumPackages = await _premiumPackageRepository._DbQueryable.ToListAsync();
        long totalUsedTokens = premiumPackages.Sum(p => p.UsedTokens);
        long totalRemainingTokens = premiumPackages.Sum(p => p.RemainingTokens);

        // 2. 计算1亿Token成本
        decimal costPerHundredMillion = totalUsedTokens > 0
            ? input.CurrentCost / (totalUsedTokens / 100000000m)
            : 0;

        // 3. 计算总成本(剩余+已使用的总成本)
        long totalTokens = totalUsedTokens + totalRemainingTokens;
        decimal totalCost = totalTokens > 0
            ? (totalTokens / 100000000m) * costPerHundredMillion
            : 0;

        // 4. 获取总收益(RechargeType=PremiumPackage的充值金额总和)
        decimal totalRevenue = await _rechargeRepository._DbQueryable
            .Where(x => x.RechargeType == Domain.Shared.Enums.RechargeTypeEnum.PremiumPackage)
            .SumAsync(x => x.RechargeAmount);

        // 5. 计算利润率
        decimal profitRate = totalCost > 0
            ? (totalRevenue / totalCost - 1) * 100
            : 0;

        // 6. 按200售价计算成本
        decimal costAt200Price = totalRevenue > 0
            ? (totalCost / totalRevenue) * 200
            : 0;

        // 7. 格式化日期
        var today = DateTime.Now;
        string dayOfWeek = today.ToString("dddd", new CultureInfo("zh-CN"));
        string weekDay = dayOfWeek switch
        {
            "星期一" => "周1",
            "星期二" => "周2",
            "星期三" => "周3",
            "星期四" => "周4",
            "星期五" => "周5",
            "星期六" => "周6",
            "星期日" => "周日",
            _ => dayOfWeek
        };

        return new ProfitStatisticsOutput
        {
            Date = $"{today:M月d日} {weekDay}",
            TotalUsedTokens = totalUsedTokens,
            TotalUsedTokensInHundredMillion = totalUsedTokens / 100000000m,
            TotalRemainingTokens = totalRemainingTokens,
            TotalRemainingTokensInHundredMillion = totalRemainingTokens / 100000000m,
            CurrentCost = input.CurrentCost,
            CostPerHundredMillion = costPerHundredMillion,
            TotalCost = totalCost,
            TotalRevenue = totalRevenue,
            ProfitRate = profitRate,
            CostAt200Price = costAt200Price
        };
    }

    /// <summary>
    /// 获取指定日期各模型Token统计
    /// </summary>
    [HttpPost("system-statistics/token")]
    public async Task<TokenStatisticsOutput> GetTokenStatisticsAsync(TokenStatisticsInput input)
    {
        var day = input.Date.Date;
        var nextDay = day.AddDays(1);

        // 1. 获取所有尊享模型(包含被禁用的),按ModelId去重
        var premiumModels = await _modelRepository._DbQueryable
            .Where(x => x.IsPremium)
            .ToListAsync();

        if (premiumModels.Count == 0)
        {
            return new TokenStatisticsOutput
            {
                Date = FormatDate(day),
                ModelStatistics = new List<ModelTokenStatisticsDto>()
            };
        }

        // 按ModelId去重,保留第一个模型的名称
        var distinctModels = premiumModels
            .GroupBy(x => x.ModelId)
            .Select(g => g.First())
            .ToList();

        var modelIds = distinctModels.Select(x => x.ModelId).ToList();

        // 2. 查询指定日期内各模型的Token使用统计
        var modelStats = await _messageRepository._DbQueryable
            .Where(x => modelIds.Contains(x.ModelId))
            .Where(x => x.CreationTime >= day && x.CreationTime < nextDay)
            .Where(x => x.Role == "system")
            .GroupBy(x => x.ModelId)
            .Select(x => new
            {
                ModelId = x.ModelId,
                Tokens = SqlFunc.AggregateSum(x.TokenUsage.TotalTokenCount),
                Count = SqlFunc.AggregateCount(x.Id)
            })
            .ToListAsync();

        var modelStatDict = modelStats.ToDictionary(x => x.ModelId, x => x);

        // 3. 构建结果列表,使用去重后的模型列表
        var result = new List<ModelTokenStatisticsDto>();
        foreach (var model in distinctModels)
        {
            modelStatDict.TryGetValue(model.ModelId, out var stat);
            long tokens = stat?.Tokens ?? 0;
            long count = stat?.Count ?? 0;

            // 这里成本设为0,因为需要前端传入或者从配置中获取
            decimal cost = 0;
            decimal costPerHundredMillion = tokens > 0 && cost > 0
                ? cost / (tokens / 100000000m)
                : 0;

            result.Add(new ModelTokenStatisticsDto
            {
                ModelId = model.ModelId,
                ModelName = model.Name,
                Tokens = tokens,
                TokensInWan = tokens / 10000m,
                Count = count,
                Cost = cost,
                CostPerHundredMillion = costPerHundredMillion
            });
        }

        return new TokenStatisticsOutput
        {
            Date = FormatDate(day),
            ModelStatistics = result
        };
    }

    private string FormatDate(DateTime date)
    {
        string dayOfWeek = date.ToString("dddd", new CultureInfo("zh-CN"));
        string weekDay = dayOfWeek switch
        {
            "星期一" => "周1",
            "星期二" => "周2",
            "星期三" => "周3",
            "星期四" => "周4",
            "星期五" => "周5",
            "星期六" => "周6",
            "星期日" => "周日",
            _ => dayOfWeek
        };
        return $"{date:M月d日} {weekDay}";
    }
}