using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Inventory.Commands;
using TakeoutSaaS.Application.App.Inventory.Dto;
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 LockInventoryCommandHandler(
    IInventoryRepository inventoryRepository,
    ITenantProvider tenantProvider,
    ILogger<LockInventoryCommandHandler> logger)
    : IRequestHandler<LockInventoryCommand, InventoryItemDto>
{
    /// <inheritdoc />
    public async Task<InventoryItemDto> Handle(LockInventoryCommand request, CancellationToken cancellationToken)
    {
        // 1. 读取库存
        var tenantId = tenantProvider.GetCurrentTenantId();
        var item = await inventoryRepository.GetForUpdateAsync(tenantId, request.StoreId, request.ProductSkuId, cancellationToken);
        if (item is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "库存不存在");
        }

        // 1.1 幂等处理
        var existingLock = await inventoryRepository.FindLockByKeyAsync(tenantId, request.IdempotencyKey, cancellationToken);
        if (existingLock is not null)
        {
            return InventoryMapping.ToDto(item);
        }

        // 2. 校验可用量
        var now = DateTime.UtcNow;
        var isPresale = request.IsPresaleOrder || item.IsPresale;
        if (isPresale)
        {
            if (item.PresaleStartTime.HasValue && now < item.PresaleStartTime.Value)
            {
                throw new BusinessException(ErrorCodes.Conflict, "预售尚未开始");
            }

            if (item.PresaleEndTime.HasValue && now > item.PresaleEndTime.Value)
            {
                throw new BusinessException(ErrorCodes.Conflict, "预售已结束");
            }
        }

        var available = isPresale
            ? (item.PresaleCapacity ?? item.QuantityOnHand) - item.PresaleLocked
            : item.QuantityOnHand - item.QuantityReserved;
        if (available < request.Quantity)
        {
            throw new BusinessException(ErrorCodes.Conflict, "库存不足，无法锁定");
        }

        // 3. 执行锁定
        if (isPresale)
        {
            item.PresaleLocked += request.Quantity;
        }
        else
        {
            item.QuantityReserved += request.Quantity;
        }

        item.IsSoldOut = item.QuantityOnHand - item.QuantityReserved - item.PresaleLocked <= (item.SafetyStock ?? 0);
        await inventoryRepository.UpdateItemAsync(item, cancellationToken);
        var lockRecord = new Domain.Inventory.Entities.InventoryLockRecord
        {
            TenantId = tenantId,
            StoreId = request.StoreId,
            ProductSkuId = request.ProductSkuId,
            Quantity = request.Quantity,
            IsPresale = isPresale,
            IdempotencyKey = request.IdempotencyKey,
            ExpiresAt = request.ExpiresAt,
            Status = Domain.Inventory.Enums.InventoryLockStatus.Locked
        };

        await inventoryRepository.AddLockAsync(lockRecord, cancellationToken);
        await inventoryRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("锁定库存 门店 {StoreId} SKU {ProductSkuId} 数量 {Quantity}", request.StoreId, request.ProductSkuId, request.Quantity);
        return InventoryMapping.ToDto(item);
    }
}
