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

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

namespace OrderService.API.Application.Commands;

/// <summary>
/// EN: Handler for processing payment and executing order items via strategies.
/// VI: Handler xử lý thanh toán và thực thi order items qua strategies.
/// </summary>
public class PayOrderCommandHandler : IRequestHandler<PayOrderCommand, PayOrderResult>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IEnumerable<ILineItemStrategy> _strategies;
    private readonly ILogger<PayOrderCommandHandler> _logger;

    public PayOrderCommandHandler(
        IOrderRepository orderRepository,
        IEnumerable<ILineItemStrategy> strategies,
        ILogger<PayOrderCommandHandler> 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<PayOrderResult> Handle(
        PayOrderCommand request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "EN: Processing payment for order {OrderId} / VI: Xử lý thanh toán cho order {OrderId}",
            request.OrderId);

        // EN: Load order
        // VI: Load order
        var order = await _orderRepository.GetByIdAsync(request.OrderId, cancellationToken);
        if (order == null)
        {
            throw new DomainException($"Order not found: {request.OrderId}");
        }

        // EN: Verify shop ownership
        // VI: Xác minh quyền sở hữu shop
        if (order.ShopId != request.ShopId)
        {
            throw new DomainException("Order does not belong to this shop");
        }

        // EN: Mark order as paid (will validate status internally)
        // VI: Đánh dấu order là đã thanh toán (sẽ validate status bên trong)
        order.MarkAsPaid();

        // EN: Execute all items via their strategies
        // VI: Thực thi tất cả items qua strategies của chúng
        foreach (var item in order.Items)
        {
            var strategy = GetStrategy(item.ProductType);
            await strategy.ExecuteAsync(item, request.ShopId, cancellationToken);

            _logger.LogInformation(
                "EN: Executed item {ProductName} via {StrategyType} / VI: Đã thực thi item {ProductName} qua {StrategyType}",
                item.ProductName,
                strategy.GetType().Name);
        }

        // EN: Mark order as processing
        // VI: Đánh dấu order là đang xử lý
        order.MarkAsProcessing();

        // EN: Save changes
        // VI: Lưu thay đổi
        await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "EN: Payment processed successfully / VI: Xử lý thanh toán thành công: {OrderId}",
            order.Id);

        return new PayOrderResult(true, 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;
    }
}
