using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;

namespace CMSMicroservice.Application.InventoryItemCQ.Commands.ReduceInventory;

public class ReduceInventoryCommandHandler : IRequestHandler<ReduceInventoryCommand, ReduceInventoryResponseDto>
{
    private readonly IApplicationDbContext _context;

    public ReduceInventoryCommandHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<ReduceInventoryResponseDto> Handle(ReduceInventoryCommand request, CancellationToken cancellationToken)
    {
        var item = await _context.InventoryItems
            .FirstOrDefaultAsync(i => i.Id == request.Id, cancellationToken);

        if (item == null)
        {
            throw new NotFoundException(nameof(Domain.Entities.InventoryItem), request.Id);
        }

        var previousQuantity = item.Quantity;

        if (request.FromReserved)
        {
            // کم کردن از موجودی رزرو شده
            if (item.ReservedQuantity < request.Quantity)
            {
                throw new InvalidOperationException($"Insufficient reserved stock. Reserved: {item.ReservedQuantity}, Requested: {request.Quantity}");
            }

            item.ReservedQuantity -= request.Quantity;
            item.Quantity -= request.Quantity;
        }
        else
        {
            // کم کردن مستقیم از موجودی
            if (item.AvailableQuantity < request.Quantity)
            {
                throw new InvalidOperationException($"Insufficient available stock. Available: {item.AvailableQuantity}, Requested: {request.Quantity}");
            }

            item.Quantity -= request.Quantity;
        }

        item.LastSoldAt = DateTime.UtcNow;

        // ثبت حرکت موجودی
        var stockMovement = new StockMovement
        {
            InventoryItemId = item.Id,
            MovementType = request.MovementType,
            Quantity = -request.Quantity,  // منفی — CHECK constraint: QuantityAfter = QuantityBefore + Quantity
            QuantityBefore = previousQuantity,
            QuantityAfter = item.Quantity,
            Note = request.Note ?? request.MovementType.ToString(),
            ReferenceNumber = request.ReferenceNumber ?? $"SALE-{DateTime.UtcNow:yyyyMMddHHmmss}",
            OrderId = request.OrderId,
            DiscountOrderId = request.DiscountOrderId,
            PerformedByUserId = request.PerformedByUserId
        };

        await _context.StockMovements.AddAsync(stockMovement, cancellationToken);

        // همگام‌سازی با Product.RemainingCount یا DiscountProduct.RemainingCount
        if (item.ProductType == ProductType.RegularProduct && item.ProductId.HasValue)
        {
            var product = await _context.Products.FindAsync(new object[] { item.ProductId.Value }, cancellationToken);
            if (product != null)
            {
                product.RemainingCount = item.Quantity;
            }
        }
        else if (item.ProductType == ProductType.DiscountProduct && item.DiscountProductId.HasValue)
        {
            var discountProduct = await _context.DiscountProducts.FindAsync(
                new object[] { item.DiscountProductId.Value }, cancellationToken);
            if (discountProduct != null)
            {
                discountProduct.RemainingCount = item.Quantity;
            }
        }

        await _context.SaveChangesAsync(cancellationToken);

        return new ReduceInventoryResponseDto { Success = true };
    }
}
