// EN: Handler for CreateOrderCommand.
// VI: Handler cho CreateOrderCommand.

using MediatR;
using OrderService.Domain.AggregatesModel.OrderAggregate;
using OrderService.Domain.Strategies;

namespace OrderService.API.Application.Commands;

/// <summary>
/// EN: Handler for creating a new order with strategy-based validation.
/// VI: Handler tạo order mới với validation qua strategy.
/// </summary>
public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, CreateOrderResult>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IEnumerable<ILineItemStrategy> _strategies;
    private readonly ILogger<CreateOrderCommandHandler> _logger;

    public CreateOrderCommandHandler(
        IOrderRepository orderRepository,
        IEnumerable<ILineItemStrategy> strategies,
        ILogger<CreateOrderCommandHandler> logger)
    {
        _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
        _strategies = strategies ?? throw new ArgumentNullException(nameof(strategies));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task<CreateOrderResult> Handle(
        CreateOrderCommand request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "EN: Creating order for shop {ShopId} / VI: Tạo order cho shop {ShopId}",
            request.ShopId);

        // EN: Create order aggregate
        // VI: Tạo order aggregate
        var order = new Order(request.ShopId, request.CustomerId);

        // EN: Add items to order
        // VI: Thêm items vào order
        foreach (var itemRequest in request.Items)
        {
            var orderItem = new OrderItem(
                itemRequest.ProductId,
                itemRequest.ProductName,
                itemRequest.ProductType,
                itemRequest.Quantity,
                itemRequest.UnitPrice);

            order.AddItem(orderItem);
        }

        // EN: Validate all items through their strategies
        // VI: Validate tất cả items qua strategies của chúng
        foreach (var item in order.Items)
        {
            var strategy = GetStrategy(item.ProductType);
            var isValid = await strategy.ValidateAsync(item, request.ShopId, cancellationToken);

            if (!isValid)
            {
                throw new InvalidOperationException(
                    $"Validation failed for item {item.ProductName} (type: {item.ProductType})");
            }
        }

        // EN: Mark order as validated after all items pass validation
        // VI: Đánh dấu order là validated sau khi tất cả items pass validation
        order.MarkAsValidated();

        // EN: Save order
        // VI: Lưu order
        _orderRepository.Add(order);
        await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "EN: Order created successfully / VI: Tạo order thành công: {OrderId}",
            order.Id);

        return new CreateOrderResult(
            order.Id,
            order.TotalAmount,
            order.Status.Name);
    }

    private ILineItemStrategy GetStrategy(string productType)
    {
        var strategy = _strategies.FirstOrDefault(s => s.SupportedType == productType);
        if (strategy == null)
        {
            throw new InvalidOperationException(
                $"EN: No strategy found for product type / VI: Không tìm thấy strategy cho loại sản phẩm: {productType}");
        }
        return strategy;
    }
}
