using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;

namespace HoneyBox.Api.BackgroundServices;

/// <summary>
/// 福利屋开奖后台服务
/// 每分钟检查一次是否有需要开奖的福利屋
/// </summary>
public class WelfareLotteryService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<WelfareLotteryService> _logger;
    private const int WelfareType = 15; // 福利屋商品类型

    public WelfareLotteryService(
        IServiceProvider serviceProvider,
        ILogger<WelfareLotteryService> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("福利屋开奖服务已启动");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await ProcessWelfareLotteryAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "福利屋开奖服务执行出错");
            }

            // 每分钟执行一次
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }

        _logger.LogInformation("福利屋开奖服务已停止");
    }

    private async Task ProcessWelfareLotteryAsync(CancellationToken stoppingToken)
    {
        using var scope = _serviceProvider.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<HoneyBoxDbContext>();

        var now = DateTime.Now;
        _logger.LogDebug("福利屋开奖检查: {Time}", now);

        // 查找需要开奖的福利屋
        // 条件: status=1, is_flw=1, is_open=0, open_time <= 当前时间
        var welfareGoods = await dbContext.Goods
            .Where(g => g.Status == 1
                && g.Type == WelfareType
                && g.IsOpen == 0
                && g.OpenTime != null
                && g.OpenTime <= now)
            .ToListAsync(stoppingToken);

        foreach (var goods in welfareGoods)
        {
            try
            {
                await ProcessSingleWelfareLotteryAsync(dbContext, goods, stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "福利屋开奖失败: GoodsId={GoodsId}, Title={Title}",
                    goods.Id, goods.Title);
            }
        }
    }

    private async Task ProcessSingleWelfareLotteryAsync(
        HoneyBoxDbContext dbContext,
        Model.Entities.Good goods,
        CancellationToken stoppingToken)
    {
        _logger.LogInformation("开始福利屋开奖: GoodsId={GoodsId}, Title={Title}",
            goods.Id, goods.Title);

        // 获取所有奖品（num=0 表示第一箱）
        var prizeList = await dbContext.GoodsItems
            .Where(gi => gi.GoodsId == goods.Id && gi.Num == 0)
            .ToListAsync(stoppingToken);

        // 添加调试日志：输出所有奖品信息
        _logger.LogInformation("福利屋奖品列表: GoodsId={GoodsId}, 奖品数量={Count}", goods.Id, prizeList.Count);
        foreach (var p in prizeList)
        {
            _logger.LogInformation("  奖品: Id={Id}, Title={Title}, GoodsType={GoodsType}, RewardId={RewardId}, Stock={Stock}, SurplusStock={SurplusStock}, ScMoney={ScMoney}",
                p.Id, p.Title, p.GoodsType, p.RewardId ?? "(空)", p.Stock, p.SurplusStock, p.ScMoney);
        }

        // 展开奖品列表（根据库存数量）
        var expandedPrizes = new List<GoodsItem>();
        foreach (var prize in prizeList)
        {
            for (int i = 0; i < prize.Stock; i++)
            {
                expandedPrizes.Add(prize);
            }
        }

        // 打乱奖品顺序
        var random = new Random();
        expandedPrizes = expandedPrizes.OrderBy(_ => random.Next()).ToList();

        // 获取所有参与用户的订单
        var participants = await dbContext.OrderItems
            .Where(oi => oi.GoodsId == goods.Id && oi.OrderType == WelfareType)
            .ToListAsync(stoppingToken);

        if (participants.Count == 0)
        {
            _logger.LogInformation("福利屋无人参与，直接结束: GoodsId={GoodsId}", goods.Id);
            goods.IsOpen = 1;
            goods.Status = 3; // 已结束
            await dbContext.SaveChangesAsync(stoppingToken);
            return;
        }

        // 打乱参与者顺序
        participants = participants.OrderBy(_ => random.Next()).ToList();

        var prizeIndex = 0;
        var prizeCount = expandedPrizes.Count;

        // 遍历所有参与者分配奖品
        foreach (var participant in participants)
        {
            using var transaction = await dbContext.Database.BeginTransactionAsync(stoppingToken);
            try
            {
                if (prizeIndex < prizeCount)
                {
                    var prize = expandedPrizes[prizeIndex];

                    // 检查库存
                    var currentStock = await dbContext.GoodsItems
                        .Where(gi => gi.Id == prize.Id)
                        .Select(gi => gi.SurplusStock)
                        .FirstOrDefaultAsync(stoppingToken);

                    if (currentStock <= 0)
                    {
                        _logger.LogWarning("奖品库存不足: PrizeId={PrizeId}", prize.Id);
                        continue;
                    }

                    // 更新订单信息
                    participant.GoodslistId = prize.Id;
                    participant.GoodslistTitle = prize.Title;
                    participant.GoodslistImgurl = prize.ImgUrl;
                    participant.GoodslistMoney = prize.Money;
                    participant.GoodslistType = prize.GoodsType;
                    participant.ShangId = prize.ShangId ?? 0;
                    participant.PrizeCode = prize.RewardId?.ToString() ?? "";

                    // 如果是实物奖品，设置状态为待发货
                    if (participant.Status != 0 && participant.GoodslistType == 1)
                    {
                        participant.Status = 0;
                        participant.RecoveryNum = "";
                    }

                    // 减少库存
                    var updateResult = await dbContext.GoodsItems
                        .Where(gi => gi.Id == prize.Id && gi.SurplusStock > 0)
                        .ExecuteUpdateAsync(s => s
                            .SetProperty(gi => gi.SurplusStock, gi => gi.SurplusStock - 1),
                            stoppingToken);

                    if (updateResult == 0)
                    {
                        _logger.LogWarning("更新库存失败: PrizeId={PrizeId}", prize.Id);
                        await transaction.RollbackAsync(stoppingToken);
                        continue;
                    }

                    // 发放奖励
                    // 添加调试日志
                    _logger.LogInformation("准备发放奖励: PrizeId={PrizeId}, Title={Title}, GoodsType={GoodsType}, RewardId={RewardId}, ScMoney={ScMoney}, UserId={UserId}",
                        prize.Id, prize.Title, prize.GoodsType, prize.RewardId ?? "(空)", prize.ScMoney, participant.UserId);
                    
                    // 1. 如果有reward_id（字符串类型奖励码），通过奖励配置发放
                    if (!string.IsNullOrEmpty(prize.RewardId))
                    {
                        _logger.LogInformation("尝试通过RewardId发放奖励: RewardId={RewardId}", prize.RewardId);
                        var rewardSent = await SendRewardByCodeAsync(dbContext, participant.UserId, prize.RewardId,
                            $"{goods.Title}开奖-{prize.Title}", stoppingToken);
                        if (rewardSent)
                        {
                            _logger.LogInformation("发放奖励成功: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, RewardCode={RewardCode}",
                                goods.Id, participant.UserId, prize.Title, prize.RewardId);
                        }
                        else
                        {
                            _logger.LogWarning("奖励配置不存在或发放失败: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, RewardCode={RewardCode}",
                                goods.Id, participant.UserId, prize.Title, prize.RewardId);
                        }
                    }
                    // 2. 如果是货币类型奖品（GoodsType=3）且没有reward_id，直接发放ScMoney金额
                    else if (prize.GoodsType == 3 && prize.ScMoney > 0)
                    {
                        _logger.LogInformation("尝试通过GoodsType=3发放货币奖品: ScMoney={ScMoney}", prize.ScMoney);
                        await SendCurrencyPrizeAsync(dbContext, participant.UserId, prize.ScMoney,
                            $"{goods.Title}开奖-{prize.Title}", stoppingToken);
                        _logger.LogInformation("发放货币奖品成功: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, Amount={Amount}",
                            goods.Id, participant.UserId, prize.Title, prize.ScMoney);
                    }
                    else
                    {
                        _logger.LogInformation("实物奖品，无需发放货币: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, GoodsType={GoodsType}",
                            goods.Id, participant.UserId, prize.Title, prize.GoodsType);
                    }

                    prizeIndex++;
                }
                else
                {
                    // 轮空处理
                    participant.GoodslistId = 0;
                    participant.GoodslistTitle = "轮空";
                    participant.GoodslistMoney = 0;
                    participant.ShangId = 0;
                    participant.PrizeCode = "";
                }

                await dbContext.SaveChangesAsync(stoppingToken);
                await transaction.CommitAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync(stoppingToken);
                _logger.LogError(ex, "处理参与者奖品失败: GoodsId={GoodsId}, UserId={UserId}",
                    goods.Id, participant.UserId);
            }
        }

        // 更新福利屋状态为已开奖
        goods.IsOpen = 1;
        goods.Status = 3; // 已结束
        await dbContext.SaveChangesAsync(stoppingToken);

        _logger.LogInformation("福利屋开奖完成: GoodsId={GoodsId}, Title={Title}, 参与人数={Count}",
            goods.Id, goods.Title, participants.Count);
    }

    /// <summary>
    /// 通过奖励码发放奖励
    /// 支持同一个 reward_id 对应多条奖励记录（如同时赠送钻石和积分）
    /// </summary>
    /// <param name="dbContext">数据库上下文</param>
    /// <param name="userId">用户ID</param>
    /// <param name="rewardCode">奖励码（字符串）</param>
    /// <param name="remark">备注</param>
    /// <param name="stoppingToken">取消令牌</param>
    /// <returns>是否成功发放</returns>
    private async Task<bool> SendRewardByCodeAsync(
        HoneyBoxDbContext dbContext,
        int userId,
        string rewardCode,
        string remark,
        CancellationToken stoppingToken)
    {
        _logger.LogInformation("SendRewardByCodeAsync开始: UserId={UserId}, RewardCode={RewardCode}", userId, rewardCode);
        
        // 通过奖励码查询所有奖励配置（同一个 reward_id 可能有多条记录）
        var rewards = await dbContext.Rewards
            .Where(r => r.RewardId == rewardCode)
            .ToListAsync(stoppingToken);

        _logger.LogInformation("查询rewards表结果: RewardCode={RewardCode}, 找到记录数={Count}", rewardCode, rewards?.Count ?? 0);

        if (rewards == null || rewards.Count == 0)
        {
            _logger.LogWarning("奖励配置不存在: RewardCode={RewardCode}", rewardCode);
            return false;
        }

        // 输出每条奖励记录的详情
        foreach (var r in rewards)
        {
            _logger.LogInformation("  奖励记录: Id={Id}, RewardId={RewardId}, RewardType={RewardType}, RewardValue={RewardValue}",
                r.Id, r.RewardId, r.RewardType, r.RewardValue);
        }

        var user = await dbContext.Users
            .Where(u => u.Id == userId)
            .FirstOrDefaultAsync(stoppingToken);

        if (user == null)
        {
            _logger.LogWarning("用户不存在: UserId={UserId}", userId);
            return false;
        }

        _logger.LogInformation("用户当前余额: UserId={UserId}, Money={Money}, Integral={Integral}, Money2={Money2}",
            userId, user.Money, user.Integral, user.Money2);

        var rewardDetails = new List<string>();

        // 遍历所有奖励记录，根据类型发放
        foreach (var reward in rewards)
        {
            switch (reward.RewardType)
            {
                case 1: // 钻石
                    user.Money += reward.RewardValue;
                    // 记录流水
                    dbContext.ProfitMoneys.Add(new ProfitMoney
                    {
                        UserId = userId,
                        ChangeMoney = reward.RewardValue,
                        Money = user.Money,
                        Type = 6, // 签到赠送/福利奖励
                        Content = remark,
                        ShareUid = 0,
                        CreatedAt = DateTime.Now
                    });
                    rewardDetails.Add($"钻石{reward.RewardValue}");
                    _logger.LogInformation("发放钻石: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
                        userId, reward.RewardValue, user.Money, remark);
                    break;

                case 2: // HH币
                    user.Integral += reward.RewardValue;
                    // 记录流水
                    dbContext.ProfitIntegrals.Add(new ProfitIntegral
                    {
                        UserId = userId,
                        ChangeMoney = reward.RewardValue,
                        Money = user.Integral,
                        Type = 4, // 抽赏奖励
                        Content = remark,
                        ShareUid = 0,
                        CreatedAt = DateTime.Now
                    });
                    rewardDetails.Add($"HH币{reward.RewardValue}");
                    _logger.LogInformation("发放HH币: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
                        userId, reward.RewardValue, user.Integral, remark);
                    break;

                case 3: // 哈尼券
                    user.Money2 = (user.Money2 ?? 0) + reward.RewardValue;
                    // 记录流水
                    dbContext.ProfitMoney2s.Add(new ProfitMoney2
                    {
                        UserId = userId,
                        ChangeMoney = reward.RewardValue,
                        Money = user.Money2 ?? 0,
                        Type = 5, // 推荐奖励/福利奖励
                        Content = remark,
                        ShareUid = 0,
                        CreatedAt = DateTime.Now
                    });
                    rewardDetails.Add($"哈尼券{reward.RewardValue}");
                    _logger.LogInformation("发放哈尼券: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
                        userId, reward.RewardValue, user.Money2, remark);
                    break;

                default:
                    _logger.LogWarning("未知奖励类型: Type={Type}, RewardCode={RewardCode}", reward.RewardType, rewardCode);
                    break;
            }
        }

        if (rewardDetails.Count == 0)
        {
            _logger.LogWarning("没有有效的奖励类型: RewardCode={RewardCode}", rewardCode);
            return false;
        }

        await dbContext.SaveChangesAsync(stoppingToken);

        _logger.LogInformation("福利屋奖励发放成功: UserId={UserId}, RewardCode={RewardCode}, Rewards={Rewards}, Remark={Remark}",
            userId, rewardCode, string.Join("+", rewardDetails), remark);

        return true;
    }

    /// <summary>
    /// 发放货币类型奖品（GoodsType=3）
    /// 货币类型奖品直接使用ScMoney字段的值作为钻石/余额发放
    /// </summary>
    private async Task SendCurrencyPrizeAsync(
        HoneyBoxDbContext dbContext,
        int userId,
        decimal amount,
        string remark,
        CancellationToken stoppingToken)
    {
        var user = await dbContext.Users
            .Where(u => u.Id == userId)
            .FirstOrDefaultAsync(stoppingToken);

        if (user == null)
        {
            _logger.LogWarning("用户不存在: UserId={UserId}", userId);
            return;
        }

        // 货币类型奖品默认发放钻石/余额
        user.Money += amount;
        _logger.LogInformation("发放货币奖品(钻石): UserId={UserId}, Amount={Amount}, Remark={Remark}", 
            userId, amount, remark);

        await dbContext.SaveChangesAsync(stoppingToken);
    }
}
