using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 库存管理实现
/// 负责奖品库存的原子扣减和并发控制
/// </summary>
public class InventoryManager : IInventoryManager
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<InventoryManager> _logger;

    /// <summary>
    /// 最大重试次数（用于并发冲突时的重试）
    /// </summary>
    private const int MaxRetryCount = 3;

    public InventoryManager(HoneyBoxDbContext dbContext, ILogger<InventoryManager> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    /// <remarks>
    /// 使用原子更新操作确保并发安全，与PHP的dec('surplus_stock')行为一致。
    /// SQL条件 surplus_stock >= quantity 确保不会出现负库存。
    /// 如果库存不足或并发冲突，返回false。
    /// </remarks>
    public async Task<bool> DeductStockAsync(int goodsItemId, int quantity = 1)
    {
        if (quantity <= 0)
        {
            _logger.LogWarning("Invalid quantity for stock deduction: {Quantity}", quantity);
            return false;
        }

        try
        {
            // 使用原子更新操作，确保并发安全
            // 只有当 surplus_stock >= quantity 时才会更新成功
            // 这与PHP的 where('surplus_stock', '>', 0)->dec('surplus_stock') 行为一致
            var rowsAffected = await _dbContext.Database.ExecuteSqlRawAsync(
                @"UPDATE goods_items 
                  SET surplus_stock = surplus_stock - {0}, 
                      updated_at = GETDATE() 
                  WHERE id = {1} AND surplus_stock >= {0}",
                quantity, goodsItemId);

            if (rowsAffected > 0)
            {
                _logger.LogDebug("Stock deducted successfully: ItemId={ItemId}, Quantity={Quantity}", 
                    goodsItemId, quantity);
                return true;
            }

            _logger.LogWarning("Stock deduction failed (insufficient stock or item not found): ItemId={ItemId}, Quantity={Quantity}", 
                goodsItemId, quantity);
            return false;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error deducting stock for item {ItemId}", goodsItemId);
            return false;
        }
    }

    /// <summary>
    /// 带重试的原子库存扣减
    /// </summary>
    /// <param name="goodsItemId">商品奖品ID</param>
    /// <param name="quantity">扣减数量</param>
    /// <param name="maxRetries">最大重试次数</param>
    /// <returns>是否扣减成功</returns>
    public async Task<bool> DeductStockWithRetryAsync(int goodsItemId, int quantity = 1, int maxRetries = MaxRetryCount)
    {
        for (int attempt = 0; attempt < maxRetries; attempt++)
        {
            var success = await DeductStockAsync(goodsItemId, quantity);
            if (success)
            {
                return true;
            }

            // 检查是否是库存不足（而非并发冲突）
            var currentStock = await GetSurplusStockAsync(goodsItemId);
            if (currentStock < quantity)
            {
                // 库存确实不足，不需要重试
                _logger.LogWarning("Stock insufficient, no retry needed: ItemId={ItemId}, CurrentStock={CurrentStock}, Required={Required}",
                    goodsItemId, currentStock, quantity);
                return false;
            }

            // 可能是并发冲突，等待后重试
            if (attempt < maxRetries - 1)
            {
                _logger.LogDebug("Stock deduction retry: ItemId={ItemId}, Attempt={Attempt}", goodsItemId, attempt + 1);
                await Task.Delay(10 * (attempt + 1)); // 递增延迟
            }
        }

        _logger.LogWarning("Stock deduction failed after {MaxRetries} retries: ItemId={ItemId}", maxRetries, goodsItemId);
        return false;
    }

    /// <inheritdoc />
    public async Task<bool> CheckStockAvailabilityAsync(int goodsItemId)
    {
        try
        {
            var item = await _dbContext.GoodsItems
                .AsNoTracking()
                .FirstOrDefaultAsync(gi => gi.Id == goodsItemId);

            return item != null && item.SurplusStock > 0;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error checking stock availability for item {ItemId}", goodsItemId);
            return false;
        }
    }

    /// <inheritdoc />
    /// <remarks>
    /// 获取可抽奖品池，过滤条件：
    /// 1. goods_id 匹配
    /// 2. num（箱号）匹配
    /// 3. surplus_stock > 0（有库存）
    /// 4. goods_list_id = 0（排除宝箱内的子奖品）
    /// 与PHP的查询逻辑保持一致
    /// </remarks>
    public async Task<List<GoodsItem>> GetAvailablePrizePoolAsync(int goodsId, int num)
    {
        try
        {
            // 查询有库存的奖品
            // goods_list_id = 0 表示排除宝箱内的子奖品（子奖品的goods_list_id指向父奖品ID）
            var prizePool = await _dbContext.GoodsItems
                .AsNoTracking()
                .Where(gi => gi.GoodsId == goodsId && 
                             gi.Num == num && 
                             gi.SurplusStock > 0 &&
                             gi.GoodsListId == 0) // 排除宝箱内的子奖品
                .OrderByDescending(gi => gi.Sort)
                .ThenBy(gi => gi.ShangId)
                .ThenBy(gi => gi.Id)
                .ToListAsync();

            _logger.LogDebug("Available prize pool for goods {GoodsId}, num {Num}: {Count} items", 
                goodsId, num, prizePool.Count);

            return prizePool;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting available prize pool for goods {GoodsId}, num {Num}", 
                goodsId, num);
            return new List<GoodsItem>();
        }
    }

    /// <summary>
    /// 获取可抽奖品池（包含宝箱内子奖品）
    /// </summary>
    /// <param name="goodsId">商品ID</param>
    /// <param name="num">箱号</param>
    /// <param name="parentGoodsListId">父奖品ID（宝箱ID）</param>
    /// <returns>可抽奖品列表</returns>
    public async Task<List<GoodsItem>> GetAvailableBoxPrizePoolAsync(int goodsId, int num, int parentGoodsListId)
    {
        try
        {
            // 查询宝箱内有库存的子奖品
            var prizePool = await _dbContext.GoodsItems
                .AsNoTracking()
                .Where(gi => gi.GoodsId == goodsId && 
                             gi.Num == num && 
                             gi.SurplusStock > 0 &&
                             gi.GoodsListId == parentGoodsListId) // 只查询指定宝箱内的子奖品
                .OrderByDescending(gi => gi.Sort)
                .ThenBy(gi => gi.ShangId)
                .ThenBy(gi => gi.Id)
                .ToListAsync();

            _logger.LogDebug("Available box prize pool for goods {GoodsId}, num {Num}, parent {ParentId}: {Count} items", 
                goodsId, num, parentGoodsListId, prizePool.Count);

            return prizePool;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting available box prize pool for goods {GoodsId}, num {Num}, parent {ParentId}", 
                goodsId, num, parentGoodsListId);
            return new List<GoodsItem>();
        }
    }

    /// <summary>
    /// 获取商品的总剩余库存
    /// </summary>
    /// <param name="goodsId">商品ID</param>
    /// <param name="num">箱号</param>
    /// <returns>总剩余库存</returns>
    public async Task<int> GetTotalSurplusStockAsync(int goodsId, int num)
    {
        try
        {
            var totalStock = await _dbContext.GoodsItems
                .AsNoTracking()
                .Where(gi => gi.GoodsId == goodsId && 
                             gi.Num == num && 
                             gi.GoodsListId == 0) // 只统计父奖品
                .SumAsync(gi => gi.SurplusStock);

            return totalStock;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting total surplus stock for goods {GoodsId}, num {Num}", 
                goodsId, num);
            return 0;
        }
    }

    /// <inheritdoc />
    public async Task<List<int>> CheckBatchStockAvailabilityAsync(List<int> goodsItemIds)
    {
        try
        {
            var availableIds = await _dbContext.GoodsItems
                .AsNoTracking()
                .Where(gi => goodsItemIds.Contains(gi.Id) && gi.SurplusStock > 0)
                .Select(gi => gi.Id)
                .ToListAsync();

            return availableIds;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error checking batch stock availability");
            return new List<int>();
        }
    }

    /// <inheritdoc />
    public async Task<int> GetSurplusStockAsync(int goodsItemId)
    {
        try
        {
            var item = await _dbContext.GoodsItems
                .AsNoTracking()
                .FirstOrDefaultAsync(gi => gi.Id == goodsItemId);

            return item?.SurplusStock ?? 0;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting surplus stock for item {ItemId}", goodsItemId);
            return 0;
        }
    }
}
