using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using SqlSugar;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos.DailyTask;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Chat;
using Yi.Framework.AiHub.Domain.Entities.Model;
using Yi.Framework.AiHub.Domain.Extensions;
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.AiHub.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace Yi.Framework.AiHub.Application.Services;

/// <summary>
/// 每日任务服务
/// </summary>
[Authorize]
public class DailyTaskService : ApplicationService
{
    private readonly ISqlSugarRepository<DailyTaskRewardRecordAggregateRoot> _dailyTaskRepository;
    private readonly ISqlSugarRepository<MessageAggregateRoot> _messageRepository;
    private readonly ISqlSugarRepository<PremiumPackageAggregateRoot> _premiumPackageRepository;
    private readonly ILogger<DailyTaskService> _logger;
    private readonly IDistributedCache<DailyTaskConfigCacheDto> _taskConfigCache;
    private IDistributedLockProvider DistributedLock => LazyServiceProvider.LazyGetRequiredService<IDistributedLockProvider>();
    private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;

    private const string TaskConfigCacheKey = "AiHub:DailyTaskConfig";

    // 默认任务配置（当Redis中没有配置时使用）
    private static readonly List<DailyTaskConfigItem> DefaultTaskConfigs = new()
    {
        new DailyTaskConfigItem { Level = 1, RequiredTokens = 10000000, RewardTokens = 1000000, Name = "尊享包1000w token任务", Description = "累积使用尊享包 1000w token" },
        new DailyTaskConfigItem { Level = 2, RequiredTokens = 30000000, RewardTokens = 2000000, Name = "尊享包3000w token任务", Description = "累积使用尊享包 3000w token" }
    };

    public DailyTaskService(
        ISqlSugarRepository<DailyTaskRewardRecordAggregateRoot> dailyTaskRepository,
        ISqlSugarRepository<MessageAggregateRoot> messageRepository,
        ISqlSugarRepository<PremiumPackageAggregateRoot> premiumPackageRepository,
        ILogger<DailyTaskService> logger,
        ISqlSugarRepository<AiModelEntity> aiModelRepository,
        IDistributedCache<DailyTaskConfigCacheDto> taskConfigCache)
    {
        _dailyTaskRepository = dailyTaskRepository;
        _messageRepository = messageRepository;
        _premiumPackageRepository = premiumPackageRepository;
        _logger = logger;
        _aiModelRepository = aiModelRepository;
        _taskConfigCache = taskConfigCache;
    }

    /// <summary>
    /// 获取今日任务状态
    /// </summary>
    /// <returns></returns>
    public async Task<DailyTaskStatusOutput> GetTodayTaskStatusAsync()
    {
        var userId = CurrentUser.GetId();
        var today = DateTime.Today;

        // 1. 获取任务配置
        var taskConfigs = await GetTaskConfigsAsync();

        // 2. 统计今日尊享包Token消耗量
        var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today);

        // 3. 查询今日已领取的任务
        var claimedTasks = await _dailyTaskRepository._DbQueryable
            .Where(x => x.UserId == userId && x.TaskDate == today)
            .Select(x => new { x.TaskLevel, x.IsRewarded })
            .ToListAsync();

        // 4. 构建任务列表
        var tasks = new List<DailyTaskItem>();
        foreach (var config in taskConfigs)
        {
            var claimed = claimedTasks.FirstOrDefault(x => x.TaskLevel == config.Level);
            int status;

            if (claimed != null && claimed.IsRewarded)
            {
                status = 2; // 已领取
            }
            else if (todayConsumed >= config.RequiredTokens)
            {
                status = 1; // 可领取
            }
            else
            {
                status = 0; // 未完成
            }

            var progress = todayConsumed >= config.RequiredTokens
                ? 100
                : Math.Round((decimal)todayConsumed / config.RequiredTokens * 100, 2);

            tasks.Add(new DailyTaskItem
            {
                Level = config.Level,
                Name = config.Name,
                Description = config.Description,
                RequiredTokens = config.RequiredTokens,
                RewardTokens = config.RewardTokens,
                Status = status,
                Progress = progress
            });
        }

        return new DailyTaskStatusOutput
        {
            TodayConsumedTokens = todayConsumed,
            Tasks = tasks
        };
    }

    /// <summary>
    /// 领取任务奖励
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task ClaimTaskRewardAsync(ClaimTaskRewardInput input)
    {
        var userId = CurrentUser.GetId();
        //自旋等待，防抖
        await using var handle =
            await DistributedLock.AcquireLockAsync($"Yi:AiHub:ClaimTaskRewardLock:{userId}");

        var today = DateTime.Today;

        // 1. 获取任务配置
        var taskConfigs = await GetTaskConfigsAsync();
        var taskConfig = taskConfigs.FirstOrDefault(x => x.Level == input.TaskLevel);

        // 2. 验证任务等级
        if (taskConfig == null)
        {
            throw new UserFriendlyException($"无效的任务等级: {input.TaskLevel}");
        }

        // 3. 检查是否已领取
        var existingRecord = await _dailyTaskRepository._DbQueryable
            .Where(x => x.UserId == userId && x.TaskDate == today && x.TaskLevel == input.TaskLevel)
            .FirstAsync();

        if (existingRecord != null)
        {
            throw new UserFriendlyException("今日该任务奖励已领取，请明天再来！");
        }

        // 4. 验证今日Token消耗是否达标
        var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today);
        if (todayConsumed < taskConfig.RequiredTokens)
        {
            throw new UserFriendlyException(
                $"Token消耗未达标！需要 {taskConfig.RequiredTokens / 10000}w，当前 {todayConsumed / 10000}w");
        }

        // 5. 创建奖励包
        var premiumPackage =
            new PremiumPackageAggregateRoot(userId, taskConfig.RewardTokens, $"每日任务:{taskConfig.Name}")
            {
                PurchaseAmount = 0,
                Remark = $"{today:yyyy-MM-dd} 每日任务奖励"
            };

        await _premiumPackageRepository.InsertAsync(premiumPackage);

        // 6. 记录领取记录
        var record = new DailyTaskRewardRecordAggregateRoot(userId, input.TaskLevel, today, taskConfig.RewardTokens)
        {
            Remark = $"完成任务{input.TaskLevel}，名称：{taskConfig.Name}，消耗 {todayConsumed / 10000}w token"
        };

        await _dailyTaskRepository.InsertAsync(record);

        _logger.LogInformation(
            $"用户 {userId} 领取每日任务 {input.TaskLevel} 奖励成功，获得 {taskConfig.RewardTokens / 10000}w tokens");
    }

    /// <summary>
    /// 获取今日尊享包Token消耗量
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="today">今日日期</param>
    /// <returns>消耗的Token总数</returns>
    private async Task<long> GetTodayPremiumTokenConsumptionAsync(Guid userId, DateTime today)
    {
        var tomorrow = today.AddDays(1);

        // 查询今日所有使用尊享包模型的消息（role=system 表示消耗）
        // 先获取所有尊享模型的ModelId列表
        var premiumModelIds = await _aiModelRepository._DbQueryable
            .Where(x => x.IsPremium)
            .Select(x => x.ModelId)
            .ToListAsync();

        var totalTokens = await _messageRepository._DbQueryable
            .Where(x => x.UserId == userId)
            .Where(x => x.Role == "system") // system角色表示实际消耗
            .Where(x => premiumModelIds.Contains(x.ModelId)) // 尊享包模型
            .Where(x => x.CreationTime >= today && x.CreationTime < tomorrow)
            .SumAsync(x => x.TokenUsage.TotalTokenCount);

        return totalTokens;
    }

    /// <summary>
    /// 从Redis获取任务配置，如果不存在则写入默认配置
    /// </summary>
    private async Task<List<DailyTaskConfigItem>> GetTaskConfigsAsync()
    {
        var cacheData = await _taskConfigCache.GetOrAddAsync(
            TaskConfigCacheKey,
            () => Task.FromResult(new DailyTaskConfigCacheDto { Tasks = DefaultTaskConfigs }),
            () => new DistributedCacheEntryOptions
            {
                // 不设置过期时间，永久缓存，需要手动更新
            }
        );

        return cacheData?.Tasks ?? DefaultTaskConfigs;
    }
}