using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Inventory.Commands;
using TakeoutSaaS.Application.App.Inventory.Dto;
using TakeoutSaaS.Domain.Inventory.Entities;
using TakeoutSaaS.Domain.Inventory.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Inventory.Handlers;

/// <summary>
/// 库存调整处理器。
/// </summary>
public sealed class AdjustInventoryCommandHandler(
    IInventoryRepository inventoryRepository,
    ITenantProvider tenantProvider,
    ILogger<AdjustInventoryCommandHandler> logger)
    : IRequestHandler<AdjustInventoryCommand, InventoryItemDto>
{
    /// <inheritdoc />
    public async Task<InventoryItemDto> Handle(AdjustInventoryCommand request, CancellationToken cancellationToken)
    {
        // 1. 读取库存
        var tenantId = tenantProvider.GetCurrentTenantId();
        var item = await inventoryRepository.GetForUpdateAsync(tenantId, request.StoreId, request.ProductSkuId, cancellationToken);
        // 2. 初始化或校验存在性
        if (item is null)
        {
            if (request.QuantityDelta < 0)
            {
                throw new BusinessException(ErrorCodes.NotFound, "库存不存在，无法扣减");
            }

            // 初始化库存记录
            item = new InventoryItem
            {
                TenantId = tenantId,
                StoreId = request.StoreId,
                ProductSkuId = request.ProductSkuId,
                QuantityOnHand = request.QuantityDelta,
                QuantityReserved = 0,
                SafetyStock = request.SafetyStock,
                IsSoldOut = false
            };
            await inventoryRepository.AddItemAsync(item, cancellationToken);
        }

        // 3. 应用调整
        var newQuantity = item.QuantityOnHand + request.QuantityDelta;
        if (newQuantity < 0)
        {
            throw new BusinessException(ErrorCodes.Conflict, "库存不足，无法扣减");
        }

        item.QuantityOnHand = newQuantity;
        item.SafetyStock = request.SafetyStock ?? item.SafetyStock;
        item.IsSoldOut = request.IsSoldOut ?? IsSoldOut(item);

        // 4. 写入调整记录
        var adjustment = new InventoryAdjustment
        {
            TenantId = tenantId,
            InventoryItemId = item.Id,
            AdjustmentType = request.AdjustmentType,
            Quantity = request.QuantityDelta,
            Reason = request.Reason,
            OperatorId = null,
            OccurredAt = DateTime.UtcNow
        };
        await inventoryRepository.AddAdjustmentAsync(adjustment, cancellationToken);
        await inventoryRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("调整库存 SKU {ProductSkuId} 门店 {StoreId} 变更 {Delta}", request.ProductSkuId, request.StoreId, request.QuantityDelta);
        return InventoryMapping.ToDto(item);
    }

    // 辅助：售罄判定
    private static bool IsSoldOut(InventoryItem item)
    {
        var available = item.QuantityOnHand - item.QuantityReserved - item.PresaleLocked;
        var safety = item.SafetyStock ?? 0;
        return available <= safety || item.QuantityOnHand <= 0;
    }
}
