using System.Security.Cryptography;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Lottery;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 抽奖引擎实现
/// 整合概率计算、权重选择、库存扣减、记录创建的完整抽奖流程
/// </summary>
public class LotteryEngine : ILotteryEngine
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly IInventoryManager _inventoryManager;
    private readonly IRewardService _rewardService;
    private readonly ILogger<LotteryEngine> _logger;
    
    /// <summary>
    /// 概率计算精度倍数（与PHP保持一致，使用100000）
    /// </summary>
    private const int ProbabilityMultiple = 100000;

    /// <summary>
    /// 最大重试次数（用于库存扣减失败时的重试）
    /// </summary>
    private const int MaxRetryCount = 3;

    /// <summary>
    /// 宝箱奖品类型
    /// </summary>
    private const int BoxPrizeType = 4;

    public LotteryEngine(
        HoneyBoxDbContext dbContext, 
        IInventoryManager inventoryManager,
        IRewardService rewardService,
        ILogger<LotteryEngine> logger)
    {
        _dbContext = dbContext;
        _inventoryManager = inventoryManager;
        _rewardService = rewardService;
        _logger = logger;
    }

    /// <inheritdoc />
    /// <remarks>
    /// 完整抽奖流程：
    /// 1. 获取可用奖品池（排除库存为0的奖品）
    /// 2. 计算概率（基于库存或真实概率）
    /// 3. 权重随机选择奖品
    /// 4. 原子扣减库存（带重试机制）
    /// 5. 创建抽奖记录
    /// 6. 处理宝箱奖品（递归抽取）
    /// 7. 返回抽奖结果
    /// </remarks>
    public async Task<LotteryDrawResult> DrawAsync(LotteryDrawRequest request)
    {
        return await DrawWithRetryAsync(request, 0);
    }

    /// <summary>
    /// 带重试机制的抽奖方法
    /// </summary>
    /// <param name="request">抽奖请求</param>
    /// <param name="retryCount">当前重试次数</param>
    /// <returns>抽奖结果</returns>
    private async Task<LotteryDrawResult> DrawWithRetryAsync(LotteryDrawRequest request, int retryCount)
    {
        var result = new LotteryDrawResult { Success = false };

        try
        {
            // 1. 获取可用奖品池
            var prizePool = await _inventoryManager.GetAvailablePrizePoolAsync(request.GoodsId, request.Num);
            
            if (!prizePool.Any())
            {
                result.ErrorMessage = "暂无可抽奖品";
                _logger.LogWarning("No available prizes for goods {GoodsId}, num {Num}", request.GoodsId, request.Num);
                return result;
            }

            // 2. 计算概率
            var probabilities = CalculateProbabilities(prizePool);
            if (!probabilities.Any())
            {
                result.ErrorMessage = "暂无可抽奖品";
                return result;
            }

            // 2.5 应用指定中奖配置过滤（有限赏带兜底）
            var designatedPrizes = await GetDesignatedPrizesAsync(request.GoodsId);
            if (designatedPrizes.Any())
            {
                probabilities = FilterPrizePoolWithFallback(probabilities, request.UserId, designatedPrizes);
                if (!probabilities.Any())
                {
                    result.ErrorMessage = "暂无可抽奖品";
                    _logger.LogWarning("No available prizes after designated filter for goods {GoodsId}, user {UserId}", 
                        request.GoodsId, request.UserId);
                    return result;
                }
            }

            // 3. 权重随机选择奖品
            var selectedPrize = SelectPrizeByWeight(probabilities);
            if (selectedPrize == null)
            {
                result.ErrorMessage = "抽奖失败，请重试";
                return result;
            }

            // 4. 原子扣减库存（带重试机制）
            var deducted = await _inventoryManager.DeductStockWithRetryAsync(selectedPrize.GoodsItemId);
            if (!deducted)
            {
                // 库存扣减失败，检查是否可以重试
                if (retryCount < MaxRetryCount)
                {
                    _logger.LogWarning("Stock deduction failed for item {ItemId}, retry {RetryCount}/{MaxRetry}", 
                        selectedPrize.GoodsItemId, retryCount + 1, MaxRetryCount);
                    return await DrawWithRetryAsync(request, retryCount + 1);
                }
                
                result.ErrorMessage = "库存不足，请稍后重试";
                _logger.LogError("Stock deduction failed after {MaxRetry} retries for item {ItemId}", 
                    MaxRetryCount, selectedPrize.GoodsItemId);
                return result;
            }

            // 5. 获取赏品等级信息
            var prizeLevel = await _dbContext.PrizeLevels.FindAsync(selectedPrize.ShangId);

            // 6. 创建抽奖记录
            var orderItem = await CreateDrawRecordInternalAsync(request, selectedPrize, prizeLevel);

            // 7. 填充结果
            result.Success = true;
            result.GoodsItemId = selectedPrize.GoodsItemId;
            result.Title = selectedPrize.Title;
            result.ImgUrl = selectedPrize.ImgUrl;
            result.ShangId = selectedPrize.ShangId;
            result.ShangTitle = prizeLevel?.Title ?? string.Empty;
            result.ShangColor = prizeLevel?.Color ?? string.Empty;
            result.Price = selectedPrize.Price;
            result.ScMoney = selectedPrize.ScMoney;
            result.PrizeCode = orderItem.PrizeCode ?? string.Empty;
            result.LuckNo = orderItem.LuckNo;
            result.DrawTime = DateTime.Now;
            result.OrderItemId = orderItem.Id;
            result.GoodsType = selectedPrize.GoodsType;
            result.Doubling = selectedPrize.Doubling;
            result.IsLingzhu = selectedPrize.IsLingzhu;
            result.ParentGoodsListId = selectedPrize.ParentGoodsListId;

            _logger.LogInformation("Draw successful: User {UserId} won prize {PrizeId} ({Title})", 
                request.UserId, selectedPrize.GoodsItemId, selectedPrize.Title);

            // 8. 处理宝箱奖品（递归抽取）
            if (selectedPrize.GoodsType == BoxPrizeType)
            {
                var boxResults = await DrawBoxPrizesAsync(request, selectedPrize.GoodsItemId);
                result.BoxPrizes = boxResults;
            }
        }
        catch (DbUpdateConcurrencyException ex)
        {
            // 并发冲突，检查是否可以重试
            if (retryCount < MaxRetryCount)
            {
                _logger.LogWarning(ex, "Concurrency conflict during draw, retry {RetryCount}/{MaxRetry}", 
                    retryCount + 1, MaxRetryCount);
                return await DrawWithRetryAsync(request, retryCount + 1);
            }
            
            _logger.LogError(ex, "Concurrency conflict after {MaxRetry} retries", MaxRetryCount);
            result.ErrorMessage = "系统繁忙，请稍后重试";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Lottery draw failed for user {UserId}, goods {GoodsId}", 
                request.UserId, request.GoodsId);
            result.ErrorMessage = "抽奖失败，请稍后重试";
        }

        return result;
    }

    /// <summary>
    /// 处理宝箱奖品的递归抽取
    /// </summary>
    /// <param name="request">原始抽奖请求</param>
    /// <param name="boxGoodsItemId">宝箱奖品ID</param>
    /// <returns>宝箱内抽取的奖品列表</returns>
    private async Task<List<LotteryDrawResult>> DrawBoxPrizesAsync(LotteryDrawRequest request, int boxGoodsItemId)
    {
        var results = new List<LotteryDrawResult>();

        try
        {
            // 获取宝箱内的奖品池
            var boxPrizePool = await _inventoryManager.GetAvailableBoxPrizePoolAsync(
                request.GoodsId, request.Num, boxGoodsItemId);

            if (!boxPrizePool.Any())
            {
                _logger.LogWarning("No prizes in box {BoxId} for goods {GoodsId}", boxGoodsItemId, request.GoodsId);
                return results;
            }

            // 计算概率
            var probabilities = CalculateProbabilities(boxPrizePool);
            if (!probabilities.Any())
            {
                return results;
            }

            // 选择奖品
            var selectedPrize = SelectPrizeByWeight(probabilities);
            if (selectedPrize == null)
            {
                return results;
            }

            // 扣减库存
            var deducted = await _inventoryManager.DeductStockWithRetryAsync(selectedPrize.GoodsItemId);
            if (!deducted)
            {
                _logger.LogWarning("Failed to deduct stock for box prize {ItemId}", selectedPrize.GoodsItemId);
                return results;
            }

            // 获取赏品等级信息
            var prizeLevel = await _dbContext.PrizeLevels.FindAsync(selectedPrize.ShangId);

            // 创建抽奖记录
            var orderItem = await CreateDrawRecordInternalAsync(request, selectedPrize, prizeLevel);

            // 构建结果
            var boxResult = new LotteryDrawResult
            {
                Success = true,
                GoodsItemId = selectedPrize.GoodsItemId,
                Title = selectedPrize.Title,
                ImgUrl = selectedPrize.ImgUrl,
                ShangId = selectedPrize.ShangId,
                ShangTitle = prizeLevel?.Title ?? string.Empty,
                ShangColor = prizeLevel?.Color ?? string.Empty,
                Price = selectedPrize.Price,
                ScMoney = selectedPrize.ScMoney,
                PrizeCode = orderItem.PrizeCode ?? string.Empty,
                LuckNo = orderItem.LuckNo,
                DrawTime = DateTime.Now,
                OrderItemId = orderItem.Id,
                GoodsType = selectedPrize.GoodsType,
                Doubling = selectedPrize.Doubling,
                IsLingzhu = selectedPrize.IsLingzhu,
                ParentGoodsListId = boxGoodsItemId
            };

            results.Add(boxResult);

            // 如果宝箱内的奖品也是宝箱，递归处理
            if (selectedPrize.GoodsType == BoxPrizeType)
            {
                var nestedResults = await DrawBoxPrizesAsync(request, selectedPrize.GoodsItemId);
                results.AddRange(nestedResults);
            }

            _logger.LogInformation("Box prize drawn: User {UserId} won prize {PrizeId} ({Title}) from box {BoxId}", 
                request.UserId, selectedPrize.GoodsItemId, selectedPrize.Title, boxGoodsItemId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to draw box prizes for box {BoxId}", boxGoodsItemId);
        }

        return results;
    }

    /// <inheritdoc />
    /// <remarks>
    /// 多次抽奖流程：
    /// 1. 循环调用DrawAsync执行单次抽奖
    /// 2. 收集所有抽奖结果
    /// 3. 如果遇到非库存相关的错误，停止继续抽奖
    /// 4. 返回所有抽奖结果（包括成功和失败的）
    /// </remarks>
    public async Task<List<LotteryDrawResult>> DrawMultipleAsync(LotteryDrawRequest request, int count)
    {
        if (count <= 0)
        {
            _logger.LogWarning("Invalid draw count: {Count}", count);
            return new List<LotteryDrawResult>();
        }

        var results = new List<LotteryDrawResult>();
        var consecutiveFailures = 0;
        const int maxConsecutiveFailures = 3;

        for (int i = 0; i < count; i++)
        {
            var result = await DrawAsync(request);
            results.Add(result);

            if (result.Success)
            {
                consecutiveFailures = 0;
            }
            else
            {
                consecutiveFailures++;

                // 如果连续失败次数过多，停止抽奖
                if (consecutiveFailures >= maxConsecutiveFailures)
                {
                    _logger.LogWarning("Stopping multi-draw after {Failures} consecutive failures", consecutiveFailures);
                    break;
                }

                // 如果是非库存相关的错误，停止继续抽奖
                if (result.ErrorMessage != null && 
                    !result.ErrorMessage.Contains("库存") &&
                    !result.ErrorMessage.Contains("繁忙"))
                {
                    _logger.LogWarning("Stopping multi-draw due to error: {Error}", result.ErrorMessage);
                    break;
                }
            }
        }

        _logger.LogInformation("Multi-draw completed: {SuccessCount}/{TotalCount} successful draws for user {UserId}, goods {GoodsId}",
            results.Count(r => r.Success), count, request.UserId, request.GoodsId);

        return results;
    }

    /// <inheritdoc />
    /// <remarks>
    /// 无限赏抽奖流程（基于真实概率 real_pro）：
    /// 1. 获取使用真实概率的奖品池
    /// 2. 计算概率（基于 real_pro 字段）
    /// 3. 权重随机选择奖品
    /// 4. 创建抽奖记录（无限赏不扣减库存）
    /// 5. 处理宝箱奖品（递归抽取）
    /// 6. 返回抽奖结果
    /// </remarks>
    public async Task<LotteryDrawResult> DrawInfiniteAsync(LotteryDrawRequest request)
    {
        var result = new LotteryDrawResult { Success = false };

        try
        {
            // 1. 获取使用真实概率的奖品池
            var probabilities = await CalculateProbabilitiesByRealProAsync(request.GoodsId, request.Num);
            
            if (!probabilities.Any())
            {
                result.ErrorMessage = "暂无可抽奖品";
                _logger.LogWarning("No available prizes with real_pro for goods {GoodsId}, num {Num}", 
                    request.GoodsId, request.Num);
                return result;
            }

            // 1.5 应用指定中奖配置过滤（无限赏严格模式，无兜底）
            var designatedPrizes = await GetDesignatedPrizesAsync(request.GoodsId);
            if (designatedPrizes.Any())
            {
                probabilities = FilterPrizePoolStrict(probabilities, request.UserId, designatedPrizes);
                if (!probabilities.Any())
                {
                    result.ErrorMessage = "暂无可抽奖品";
                    _logger.LogWarning("No available prizes after strict designated filter for goods {GoodsId}, user {UserId}", 
                        request.GoodsId, request.UserId);
                    return result;
                }
            }

            // 2. 权重随机选择奖品（使用真实概率）
            var selectedPrize = SelectPrizeByRealPro(probabilities);
            if (selectedPrize == null)
            {
                result.ErrorMessage = "抽奖失败，请重试";
                return result;
            }

            // 3. 获取赏品等级信息
            var prizeLevel = await _dbContext.PrizeLevels.FindAsync(selectedPrize.ShangId);

            // 4. 创建抽奖记录（无限赏不扣减库存，因为是无限池）
            var orderItem = await CreateDrawRecordInternalAsync(request, selectedPrize, prizeLevel);

            // 5. 填充结果
            result.Success = true;
            result.GoodsItemId = selectedPrize.GoodsItemId;
            result.Title = selectedPrize.Title;
            result.ImgUrl = selectedPrize.ImgUrl;
            result.ShangId = selectedPrize.ShangId;
            result.ShangTitle = prizeLevel?.Title ?? string.Empty;
            result.ShangColor = prizeLevel?.Color ?? string.Empty;
            result.Price = selectedPrize.Price;
            result.ScMoney = selectedPrize.ScMoney;
            result.PrizeCode = orderItem.PrizeCode ?? string.Empty;
            result.LuckNo = orderItem.LuckNo;
            result.DrawTime = DateTime.Now;
            result.OrderItemId = orderItem.Id;
            result.GoodsType = selectedPrize.GoodsType;
            result.Doubling = selectedPrize.Doubling;
            result.IsLingzhu = selectedPrize.IsLingzhu;
            result.ParentGoodsListId = selectedPrize.ParentGoodsListId;

            _logger.LogInformation("Infinite draw successful: User {UserId} won prize {PrizeId} ({Title})", 
                request.UserId, selectedPrize.GoodsItemId, selectedPrize.Title);

            // 6. 处理宝箱奖品（递归抽取）
            if (selectedPrize.GoodsType == BoxPrizeType)
            {
                var boxResults = await DrawInfiniteBoxPrizesAsync(request, selectedPrize.GoodsItemId);
                result.BoxPrizes = boxResults;
            }

            // 7. 处理领主赏逻辑（type=8）
            await ProcessLingZhuLogicAsync(request.UserId, request.GoodsId, selectedPrize.ShangId, selectedPrize.IsLingzhu, orderItem.Id);

            // 8. 处理翻倍赏逻辑（doubling > 1 时赠送积分）
            await ProcessDoublingRewardAsync(request.UserId, selectedPrize.Doubling, selectedPrize.Price, selectedPrize.Title);

            // 9. 处理奖品绑定奖励发放
            await ProcessPrizeRewardAsync(request.UserId, selectedPrize.RewardId, selectedPrize.Title);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Infinite lottery draw failed for user {UserId}, goods {GoodsId}", 
                request.UserId, request.GoodsId);
            result.ErrorMessage = "抽奖失败，请稍后重试";
        }

        return result;
    }

    /// <summary>
    /// 处理领主赏逻辑
    /// </summary>
    private async Task ProcessLingZhuLogicAsync(int userId, int goodsId, int? shangId, int isLingzhu, int orderItemId)
    {
        try
        {
            // 获取商品的领主赏配置
            var goods = await _dbContext.Goods
                .Where(g => g.Id == goodsId && g.DeletedAt == null)
                .Select(g => new { g.Type, g.LingzhuIs, g.LingzhuShangId, g.KingUserId, g.LingzhuFan })
                .FirstOrDefaultAsync();

            // 只有领主赏类型(type=8)且开启了领主功能才处理
            if (goods == null || goods.Type != 8 || goods.LingzhuIs != 1)
            {
                return;
            }

            // 检查是否抽中领主奖品
            bool isLingzhuPrize = (shangId == goods.LingzhuShangId) || (isLingzhu == 1);

            if (isLingzhuPrize)
            {
                // 抽中领主奖品 - 成为新领主
                var currentTimestamp = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();

                // 如果当前有领主，结束其领主记录
                if (goods.KingUserId > 0)
                {
                    var currentKingRank = await _dbContext.GoodsKingRanks
                        .Where(r => r.UserId == goods.KingUserId && r.GoodsId == goodsId && r.EndTime == 0)
                        .OrderByDescending(r => r.Id)
                        .FirstOrDefaultAsync();

                    if (currentKingRank != null)
                    {
                        currentKingRank.EndTime = currentTimestamp;
                    }
                }

                // 更新商品的领主用户
                await _dbContext.Goods
                    .Where(g => g.Id == goodsId)
                    .ExecuteUpdateAsync(s => s.SetProperty(g => g.KingUserId, userId));

                // 计算多少发晋升领主
                var luckNo = await _dbContext.OrderItems
                    .Where(oi => oi.GoodsId == goodsId && oi.Id <= orderItemId)
                    .CountAsync();

                // 创建新的领主记录
                var newKingRank = new GoodsKingRank
                {
                    UserId = userId,
                    GoodsId = goodsId,
                    Count = luckNo,
                    OrderListId = orderItemId,
                    Addtime = currentTimestamp,
                    EndTime = 0,
                    ZNums = 0,
                    Money = 0
                };
                _dbContext.GoodsKingRanks.Add(newKingRank);
                await _dbContext.SaveChangesAsync();

                _logger.LogInformation("New king crowned: UserId={UserId}, GoodsId={GoodsId}, LuckNo={LuckNo}",
                    userId, goodsId, luckNo);
            }
            else
            {
                // 未抽中领主奖品 - 增加当前领主的被挑战次数
                if (goods.KingUserId > 0)
                {
                    var kingRank = await _dbContext.GoodsKingRanks
                        .Where(r => r.UserId == goods.KingUserId && r.GoodsId == goodsId && r.EndTime == 0)
                        .OrderByDescending(r => r.Id)
                        .FirstOrDefaultAsync();

                    // 如果没有领主记录（可能是从旧系统迁移的），创建一条初始记录
                    if (kingRank == null)
                    {
                        kingRank = new GoodsKingRank
                        {
                            UserId = goods.KingUserId,
                            GoodsId = goodsId,
                            Count = 0, // 未知占领时的抽奖次数
                            OrderListId = 0,
                            Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                            EndTime = 0,
                            ZNums = 0,
                            Money = 0
                        };
                        _dbContext.GoodsKingRanks.Add(kingRank);
                        _logger.LogInformation("Created initial king rank record for migrated king: UserId={UserId}, GoodsId={GoodsId}",
                            goods.KingUserId, goodsId);
                    }

                    kingRank.ZNums += 1;

                    // 领主收益（如果配置了）
                    if (goods.LingzhuFan > 0)
                    {
                        kingRank.Money += goods.LingzhuFan;

                        // 给领主增加积分收益
                        var kingUser = await _dbContext.Users.FindAsync(goods.KingUserId);
                        if (kingUser != null)
                        {
                            var beforeIntegral = kingUser.Integral;
                            kingUser.Integral += goods.LingzhuFan;

                            // 记录积分流水
                            var profitIntegral = new ProfitIntegral
                            {
                                UserId = goods.KingUserId,
                                Type = 4, // 领主收益
                                ChangeMoney = goods.LingzhuFan,
                                Money = kingUser.Integral,
                                Content = "领主收益",
                                ShareUid = 0,
                                CreatedAt = DateTime.Now
                            };
                            _dbContext.ProfitIntegrals.Add(profitIntegral);
                        }
                    }

                    await _dbContext.SaveChangesAsync();
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process lingzhu logic: UserId={UserId}, GoodsId={GoodsId}",
                userId, goodsId);
            // 领主逻辑失败不影响抽奖结果
        }
    }

    /// <summary>
    /// 处理翻倍赏逻辑 - 当奖品doubling > 1时，赠送用户额外积分
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="doubling">翻倍倍数</param>
    /// <param name="prizePrice">奖品价格</param>
    /// <param name="prizeTitle">奖品标题</param>
    private async Task ProcessDoublingRewardAsync(int userId, int doubling, decimal prizePrice, string prizeTitle)
    {
        try
        {
            // 只有翻倍倍数大于1才赠送
            if (doubling <= 1)
            {
                return;
            }

            // 计算赠送积分：奖品价格 * (倍数-1) * 100
            var bei = doubling - 1;
            var rewardIntegral = prizePrice * bei * 100;

            if (rewardIntegral <= 0)
            {
                return;
            }

            // 更新用户积分
            var user = await _dbContext.Users.FindAsync(userId);
            if (user == null)
            {
                return;
            }

            user.Integral += rewardIntegral;

            // 记录积分流水
            var profitIntegral = new ProfitIntegral
            {
                UserId = userId,
                Type = 6, // 翻倍赏赠送
                ChangeMoney = rewardIntegral,
                Money = user.Integral,
                Content = $"抽中翻倍赏-{prizeTitle}赠送",
                ShareUid = 0,
                CreatedAt = DateTime.Now
            };
            _dbContext.ProfitIntegrals.Add(profitIntegral);

            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("Doubling reward granted: UserId={UserId}, Doubling={Doubling}, Reward={Reward}, Prize={Prize}",
                userId, doubling, rewardIntegral, prizeTitle);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process doubling reward: UserId={UserId}, Doubling={Doubling}",
                userId, doubling);
            // 翻倍赏逻辑失败不影响抽奖结果
        }
    }

    /// <summary>
    /// 处理奖品绑定奖励发放
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="rewardId">奖励ID</param>
    /// <param name="prizeTitle">奖品标题</param>
    private async Task ProcessPrizeRewardAsync(int userId, string? rewardId, string prizeTitle)
    {
        try
        {
            // 如果没有绑定奖励，直接返回
            if (string.IsNullOrWhiteSpace(rewardId))
            {
                return;
            }

            // 调用奖励服务发放奖励
            var result = await _rewardService.SendRewardAsync(userId, rewardId, $"抽中奖品-{prizeTitle}");

            if (result.Success)
            {
                _logger.LogInformation("Prize reward sent: UserId={UserId}, RewardId={RewardId}, Prize={Prize}",
                    userId, rewardId, prizeTitle);
            }
            else
            {
                _logger.LogWarning("Prize reward failed: UserId={UserId}, RewardId={RewardId}, Message={Message}",
                    userId, rewardId, result.Message);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process prize reward: UserId={UserId}, RewardId={RewardId}",
                userId, rewardId);
            // 奖励发放失败不影响抽奖结果
        }
    }

    /// <inheritdoc />
    /// <remarks>
    /// 多次无限赏抽奖流程：
    /// 1. 循环调用DrawInfiniteAsync执行单次抽奖
    /// 2. 收集所有抽奖结果
    /// 3. 如果遇到错误，停止继续抽奖
    /// 4. 返回所有抽奖结果
    /// </remarks>
    public async Task<List<LotteryDrawResult>> DrawInfiniteMultipleAsync(LotteryDrawRequest request, int count)
    {
        if (count <= 0)
        {
            _logger.LogWarning("Invalid draw count: {Count}", count);
            return new List<LotteryDrawResult>();
        }

        var results = new List<LotteryDrawResult>();
        var consecutiveFailures = 0;
        const int maxConsecutiveFailures = 3;

        for (int i = 0; i < count; i++)
        {
            var result = await DrawInfiniteAsync(request);
            results.Add(result);

            if (result.Success)
            {
                consecutiveFailures = 0;
            }
            else
            {
                consecutiveFailures++;

                // 如果连续失败次数过多，停止抽奖
                if (consecutiveFailures >= maxConsecutiveFailures)
                {
                    _logger.LogWarning("Stopping infinite multi-draw after {Failures} consecutive failures", consecutiveFailures);
                    break;
                }
            }
        }

        _logger.LogInformation("Infinite multi-draw completed: {SuccessCount}/{TotalCount} successful draws for user {UserId}, goods {GoodsId}",
            results.Count(r => r.Success), count, request.UserId, request.GoodsId);

        return results;
    }

    /// <summary>
    /// 处理无限赏宝箱奖品的递归抽取
    /// </summary>
    /// <param name="request">原始抽奖请求</param>
    /// <param name="boxGoodsItemId">宝箱奖品ID</param>
    /// <returns>宝箱内抽取的奖品列表</returns>
    private async Task<List<LotteryDrawResult>> DrawInfiniteBoxPrizesAsync(LotteryDrawRequest request, int boxGoodsItemId)
    {
        var results = new List<LotteryDrawResult>();

        try
        {
            // 获取宝箱内使用真实概率的奖品池
            var boxPrizePool = await _dbContext.GoodsItems
                .AsNoTracking()
                .Where(gi => gi.GoodsId == request.GoodsId && 
                             gi.Num == request.Num && 
                             gi.RealPro > 0 &&
                             gi.GoodsListId == boxGoodsItemId)
                .ToListAsync();

            if (!boxPrizePool.Any())
            {
                _logger.LogWarning("No prizes with real_pro in box {BoxId} for goods {GoodsId}", 
                    boxGoodsItemId, request.GoodsId);
                return results;
            }

            // 计算概率
            var probabilities = CalculateProbabilitiesByRealPro(boxPrizePool);
            if (!probabilities.Any())
            {
                return results;
            }

            // 选择奖品
            var selectedPrize = SelectPrizeByRealPro(probabilities);
            if (selectedPrize == null)
            {
                return results;
            }

            // 获取赏品等级信息
            var prizeLevel = await _dbContext.PrizeLevels.FindAsync(selectedPrize.ShangId);

            // 创建抽奖记录
            var orderItem = await CreateDrawRecordInternalAsync(request, selectedPrize, prizeLevel);

            // 构建结果
            var boxResult = new LotteryDrawResult
            {
                Success = true,
                GoodsItemId = selectedPrize.GoodsItemId,
                Title = selectedPrize.Title,
                ImgUrl = selectedPrize.ImgUrl,
                ShangId = selectedPrize.ShangId,
                ShangTitle = prizeLevel?.Title ?? string.Empty,
                ShangColor = prizeLevel?.Color ?? string.Empty,
                Price = selectedPrize.Price,
                ScMoney = selectedPrize.ScMoney,
                PrizeCode = orderItem.PrizeCode ?? string.Empty,
                LuckNo = orderItem.LuckNo,
                DrawTime = DateTime.Now,
                OrderItemId = orderItem.Id,
                GoodsType = selectedPrize.GoodsType,
                Doubling = selectedPrize.Doubling,
                IsLingzhu = selectedPrize.IsLingzhu,
                ParentGoodsListId = boxGoodsItemId
            };

            results.Add(boxResult);

            // 如果宝箱内的奖品也是宝箱，递归处理
            if (selectedPrize.GoodsType == BoxPrizeType)
            {
                var nestedResults = await DrawInfiniteBoxPrizesAsync(request, selectedPrize.GoodsItemId);
                results.AddRange(nestedResults);
            }

            _logger.LogInformation("Infinite box prize drawn: User {UserId} won prize {PrizeId} ({Title}) from box {BoxId}", 
                request.UserId, selectedPrize.GoodsItemId, selectedPrize.Title, boxGoodsItemId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to draw infinite box prizes for box {BoxId}", boxGoodsItemId);
        }

        return results;
    }

    /// <inheritdoc />
    public async Task<List<PrizeProbability>> CalculateProbabilitiesAsync(int goodsId, int num)
    {
        var prizePool = await _inventoryManager.GetAvailablePrizePoolAsync(goodsId, num);
        return CalculateProbabilities(prizePool);
    }

    /// <inheritdoc />
    public async Task<List<PrizeProbability>> CalculateProbabilitiesByRealProAsync(int goodsId, int num)
    {
        // 获取使用真实概率的奖品池（无限赏等）
        var prizePool = await _dbContext.GoodsItems
            .AsNoTracking()
            .Where(gi => gi.GoodsId == goodsId && 
                         gi.Num == num && 
                         gi.RealPro > 0 &&
                         gi.GoodsListId == 0) // 排除宝箱内的子奖品
            .ToListAsync();
        
        return CalculateProbabilitiesByRealPro(prizePool);
    }

    /// <inheritdoc />
    public async Task<bool> ValidateDrawResultAsync(LotteryDrawResult result)
    {
        if (!result.Success)
            return false;

        // 验证订单详情记录是否存在
        var orderItem = await _dbContext.OrderItems.FindAsync(result.OrderItemId);
        return orderItem != null;
    }

    #region Public Interface Methods

    /// <inheritdoc />
    public async Task<OrderItem> CreateDrawRecordAsync(LotteryDrawRequest request, PrizeProbability prize)
    {
        // 获取赏品等级信息
        var prizeLevel = await _dbContext.PrizeLevels.FindAsync(prize.ShangId);
        return await CreateDrawRecordInternalAsync(request, prize, prizeLevel);
    }

    /// <inheritdoc />
    public string GeneratePrizeCode()
    {
        return GeneratePrizeCodeInternal();
    }

    /// <inheritdoc />
    public async Task<int> GenerateLuckNoAsync(int goodsId, int num)
    {
        return await GenerateLuckNoInternalAsync(goodsId, num);
    }

    #endregion

    #region Private Methods

    /// <summary>
    /// 计算奖品概率（基于库存）
    /// 概率公式：单个奖品概率 = (该奖品剩余库存 / 所有可抽奖品总剩余库存) * 100%
    /// </summary>
    /// <param name="prizePool">奖品池</param>
    /// <returns>奖品概率列表</returns>
    private List<PrizeProbability> CalculateProbabilities(List<GoodsItem> prizePool)
    {
        // 过滤掉库存为0的奖品
        var validPrizes = prizePool.Where(p => p.SurplusStock > 0).ToList();
        
        if (!validPrizes.Any())
            return new List<PrizeProbability>();

        var totalStock = validPrizes.Sum(p => p.SurplusStock);
        if (totalStock == 0)
            return new List<PrizeProbability>();

        return validPrizes.Select(p => new PrizeProbability
        {
            GoodsItemId = p.Id,
            Title = p.Title,
            ImgUrl = p.ImgUrl,
            ShangId = p.ShangId ?? 0,
            SurplusStock = p.SurplusStock,
            // 概率 = surplus_stock / total_surplus_stock * 100
            Probability = (decimal)p.SurplusStock / totalStock * 100,
            // 权重直接使用库存数量
            Weight = p.SurplusStock,
            Price = p.Price,
            ScMoney = p.ScMoney,
            GoodsType = p.GoodsType,
            Doubling = p.Doubling,
            IsLingzhu = p.IsLingzhu,
            ParentGoodsListId = p.GoodsListId,
            SaleTime = p.SaleTime,
            RewardId = p.RewardId
        }).ToList();
    }

    /// <summary>
    /// 计算奖品概率（基于真实概率 real_pro）
    /// 用于无限赏等使用固定概率的抽奖类型
    /// </summary>
    /// <param name="prizePool">奖品池</param>
    /// <returns>奖品概率列表</returns>
    private List<PrizeProbability> CalculateProbabilitiesByRealPro(List<GoodsItem> prizePool)
    {
        // 过滤掉概率为0的奖品
        var validPrizes = prizePool.Where(p => p.RealPro > 0).ToList();
        
        if (!validPrizes.Any())
            return new List<PrizeProbability>();

        var totalProbability = validPrizes.Sum(p => p.RealPro);
        if (totalProbability == 0)
            return new List<PrizeProbability>();

        return validPrizes.Select(p => new PrizeProbability
        {
            GoodsItemId = p.Id,
            Title = p.Title,
            ImgUrl = p.ImgUrl,
            ShangId = p.ShangId ?? 0,
            SurplusStock = p.SurplusStock,
            // 概率直接使用 real_pro
            Probability = p.RealPro,
            // 权重使用 real_pro
            Weight = (double)p.RealPro,
            Price = p.Price,
            ScMoney = p.ScMoney,
            GoodsType = p.GoodsType,
            Doubling = p.Doubling,
            IsLingzhu = p.IsLingzhu,
            ParentGoodsListId = p.GoodsListId,
            SaleTime = p.SaleTime,
            RewardId = p.RewardId
        }).ToList();
    }

    /// <summary>
    /// 权重随机选择奖品
    /// 使用加权随机算法，与PHP的weightedRandom方法保持一致
    /// </summary>
    /// <param name="probabilities">奖品概率列表</param>
    /// <returns>选中的奖品</returns>
    private PrizeProbability? SelectPrizeByWeight(List<PrizeProbability> probabilities)
    {
        if (!probabilities.Any())
            return null;

        // 计算总权重
        var totalWeight = probabilities.Sum(p => p.Weight);
        if (totalWeight <= 0)
            return null;

        // 使用加密安全的随机数生成器（与PHP的random_int保持一致）
        // 生成随机数 [1, totalWeight]
        var randomValue = GenerateSecureRandomDouble() * totalWeight;

        // 累加权重，找到命中的奖品
        // 与PHP的weightedRandom算法保持一致
        double currentWeight = 0;
        foreach (var prize in probabilities)
        {
            currentWeight += prize.Weight;
            if (randomValue < currentWeight)
            {
                return prize;
            }
        }

        // 兜底返回第一个（防止浮点数精度问题）
        return probabilities.First();
    }

    /// <summary>
    /// 权重随机选择奖品（基于真实概率）
    /// 用于无限赏等使用固定概率的抽奖类型
    /// </summary>
    /// <param name="probabilities">奖品概率列表</param>
    /// <returns>选中的奖品</returns>
    private PrizeProbability? SelectPrizeByRealPro(List<PrizeProbability> probabilities)
    {
        if (!probabilities.Any())
            return null;

        // 计算总概率
        var totalProbability = probabilities.Sum(p => p.Weight);
        if (totalProbability <= 0)
            return null;

        // 使用与PHP相同的精度倍数
        var maxRand = (long)(totalProbability * ProbabilityMultiple);
        var randomValue = GenerateSecureRandomLong(0, maxRand) / (double)ProbabilityMultiple;

        // 构建概率区间并查找中奖奖品
        double currentRange = 0;
        foreach (var prize in probabilities)
        {
            var rangeStart = currentRange;
            currentRange += prize.Weight;
            
            if (randomValue >= rangeStart && randomValue < currentRange)
            {
                return prize;
            }
        }

        // 兜底返回第一个
        return probabilities.First();
    }

    /// <summary>
    /// 生成加密安全的随机双精度浮点数 [0, 1)
    /// </summary>
    private static double GenerateSecureRandomDouble()
    {
        var bytes = new byte[8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(bytes);
        }
        // 将字节转换为 [0, 1) 范围的双精度浮点数
        var value = BitConverter.ToUInt64(bytes, 0);
        return (double)value / ulong.MaxValue;
    }

    /// <summary>
    /// 生成加密安全的随机长整数 [min, max]
    /// </summary>
    private static long GenerateSecureRandomLong(long min, long max)
    {
        if (min >= max)
            return min;

        var range = (ulong)(max - min);
        var bytes = new byte[8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(bytes);
        }
        var value = BitConverter.ToUInt64(bytes, 0);
        return min + (long)(value % (range + 1));
    }

    /// <summary>
    /// 创建抽奖记录（内部方法）
    /// </summary>
    private async Task<OrderItem> CreateDrawRecordInternalAsync(
        LotteryDrawRequest request, 
        PrizeProbability prize, 
        PrizeLevel? prizeLevel)
    {
        // 生成唯一奖品编码
        var prizeCode = GeneratePrizeCodeInternal();

        // 生成幸运号码
        var luckNo = await GenerateLuckNoInternalAsync(request.GoodsId, request.Num);

        // 计算销售时间戳
        var saleTimeStamp = prize.SaleTime.HasValue 
            ? (int)new DateTimeOffset(prize.SaleTime.Value).ToUnixTimeSeconds() 
            : 0;

        var orderItem = new OrderItem
        {
            OrderId = request.OrderId,
            UserId = request.UserId,
            GoodsId = request.GoodsId,
            Num = request.Num,
            ShangId = prize.ShangId,
            GoodslistId = prize.GoodsItemId,
            GoodslistTitle = prize.Title,
            GoodslistImgurl = prize.ImgUrl,
            GoodslistPrice = prize.Price,
            GoodslistMoney = prize.ScMoney,
            GoodslistType = (byte)prize.GoodsType,
            GoodslistSaleTime = saleTimeStamp,
            Status = 0, // 待处理
            Addtime = (int)DateTimeOffset.Now.ToUnixTimeSeconds(),
            OrderType = (byte)request.OrderType,
            Source = (byte)request.Source,
            PrizeCode = prizeCode,
            LuckNo = luckNo,
            Doubling = prize.Doubling,
            IsLingzhu = (byte)prize.IsLingzhu,
            ParentGoodsListId = prize.ParentGoodsListId,
            CreatedAt = DateTime.Now,
            UpdatedAt = DateTime.Now
        };

        _dbContext.OrderItems.Add(orderItem);
        await _dbContext.SaveChangesAsync();

        return orderItem;
    }

    /// <summary>
    /// 生成唯一奖品编码（内部方法）
    /// </summary>
    private static string GeneratePrizeCodeInternal()
    {
        var randomSuffix = GenerateSecureRandomLong(1000, 9999);
        return $"P{DateTime.Now:yyyyMMddHHmmss}{randomSuffix}";
    }

    /// <summary>
    /// 生成幸运号码（内部方法）
    /// </summary>
    private async Task<int> GenerateLuckNoInternalAsync(int goodsId, int num)
    {
        // 获取当前商品箱号的最大幸运号码
        var maxLuckNo = await _dbContext.OrderItems
            .Where(oi => oi.GoodsId == goodsId && oi.Num == num)
            .MaxAsync(oi => (int?)oi.LuckNo) ?? 0;

        return maxLuckNo + 1;
    }

    #endregion

    #region Designated Prize Methods

    /// <summary>
    /// 获取指定中奖配置
    /// 返回 Dictionary&lt;GoodsItemId, UserId&gt;，只查询 is_active = true 的配置
    /// </summary>
    /// <param name="goodsId">商品ID</param>
    /// <returns>指定中奖配置字典（GoodsItemId → UserId）</returns>
    /// <remarks>
    /// 异常降级处理：查询失败时返回空字典，不影响正常抽奖流程
    /// </remarks>
    private async Task<Dictionary<int, int>> GetDesignatedPrizesAsync(int goodsId)
    {
        try
        {
            return await _dbContext.GoodsDesignatedPrizes
                .AsNoTracking()
                .Where(dp => dp.GoodsId == goodsId && dp.IsActive)
                .ToDictionaryAsync(dp => dp.GoodsItemId, dp => dp.UserId);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to query designated prizes for goods {GoodsId}, falling back to no configuration", goodsId);
            return new Dictionary<int, int>();
        }
    }

    /// <summary>
    /// 有限赏奖品池过滤方法（带兜底机制）
    /// 分离普通奖品和指定奖品，根据用户身份返回可抽奖品池
    /// </summary>
    /// <param name="prizePool">原始奖品池</param>
    /// <param name="userId">当前用户ID</param>
    /// <param name="designatedPrizes">指定中奖配置（GoodsItemId → UserId）</param>
    /// <returns>过滤后的奖品池</returns>
    /// <remarks>
    /// 规则：
    /// 1. 指定用户：返回普通奖品 + 自己的指定奖品
    /// 2. 普通用户：优先返回普通奖品池
    /// 3. 兜底：普通奖品池为空时返回全部奖品池（记录Warning日志）
    /// </remarks>
    public List<PrizeProbability> FilterPrizePoolWithFallback(
        List<PrizeProbability> prizePool, 
        int userId, 
        Dictionary<int, int> designatedPrizes)
    {
        if (!designatedPrizes.Any())
        {
            return prizePool;
        }

        // 分离普通奖品和指定奖品
        var normalPrizes = new List<PrizeProbability>();
        var userDesignatedPrizes = new List<PrizeProbability>();

        foreach (var prize in prizePool)
        {
            if (designatedPrizes.TryGetValue(prize.GoodsItemId, out var designatedUserId))
            {
                // 这是指定奖品
                if (designatedUserId == userId)
                {
                    // 当前用户是指定用户，可以抽这个奖品
                    userDesignatedPrizes.Add(prize);
                }
                // 其他用户的指定奖品不加入池中
            }
            else
            {
                // 普通奖品
                normalPrizes.Add(prize);
            }
        }

        // 构建结果池
        var resultPool = new List<PrizeProbability>();
        resultPool.AddRange(normalPrizes);
        resultPool.AddRange(userDesignatedPrizes);

        // 兜底机制：如果结果池为空（只剩其他用户的指定奖品），返回全部奖品池
        if (!resultPool.Any() && prizePool.Any())
        {
            _logger.LogWarning(
                "Finite lottery fallback triggered: Normal prize pool is empty for user {UserId}, allowing all prizes. " +
                "Total prizes: {TotalCount}, Designated prizes: {DesignatedCount}",
                userId, prizePool.Count, designatedPrizes.Count);
            return prizePool;
        }

        return resultPool;
    }

    /// <summary>
    /// 无限赏奖品池过滤方法（严格模式，无兜底）
    /// 移除所有非当前用户的指定奖品，保留当前用户的指定奖品
    /// </summary>
    /// <param name="prizePool">原始奖品池</param>
    /// <param name="userId">当前用户ID</param>
    /// <param name="designatedPrizes">指定中奖配置（GoodsItemId → UserId）</param>
    /// <returns>过滤后的奖品池</returns>
    /// <remarks>
    /// 规则：
    /// 1. 移除所有非当前用户的指定奖品
    /// 2. 保留当前用户的指定奖品
    /// 3. 无兜底机制（指定奖品严格保护）
    /// </remarks>
    public List<PrizeProbability> FilterPrizePoolStrict(
        List<PrizeProbability> prizePool, 
        int userId, 
        Dictionary<int, int> designatedPrizes)
    {
        if (!designatedPrizes.Any())
        {
            return prizePool;
        }

        var resultPool = new List<PrizeProbability>();

        foreach (var prize in prizePool)
        {
            if (designatedPrizes.TryGetValue(prize.GoodsItemId, out var designatedUserId))
            {
                // 这是指定奖品
                if (designatedUserId == userId)
                {
                    // 当前用户是指定用户，保留这个奖品
                    resultPool.Add(prize);
                }
                // 其他用户的指定奖品不加入池中（严格过滤）
            }
            else
            {
                // 普通奖品，保留
                resultPool.Add(prize);
            }
        }

        return resultPool;
    }

    #endregion
}
