using MediatR;

namespace foodmarket.Application.Sales.Commands;

/// <summary>CQRS-образец №3 (TD-1): команда проведения чека. Handler
/// инкапсулирует валидацию платежа (вынесенную в Application слое уже
/// раньше как RetailPaymentValidator) и делегирует stock-операцию
/// абстракции IRetailSalePoster.
///
/// Цель — показать, что Post можно тестировать чисто (без БД, без
/// контроллера), проверяя бизнес-логику payment-validation + invocation
/// stock writer'а. Сам RetailSalesController остаётся как образец до-CQRS
/// контроллера (рефакторинг — отдельный спринт).</summary>
public record PostRetailSaleCommand(
    Guid SaleId,
    decimal PaidCash,
    decimal PaidCard,
    decimal Total,
    IReadOnlyList<PostSaleLine> Lines) : IRequest<PostRetailSaleResult>;

public record PostSaleLine(Guid ProductId, decimal Quantity, decimal UnitPrice);

public record PostRetailSaleResult(bool Posted, string? ErrorMessage, string? ErrorField);

/// <summary>Абстракция: списать стоки и пометить чек проведённым.</summary>
public interface IRetailSalePoster
{
    Task PostAsync(Guid saleId, IReadOnlyList<PostSaleLine> lines, CancellationToken ct);
}

public sealed class PostRetailSaleHandler : IRequestHandler<PostRetailSaleCommand, PostRetailSaleResult>
{
    private readonly IRetailSalePoster _poster;
    public PostRetailSaleHandler(IRetailSalePoster poster) => _poster = poster;

    public async Task<PostRetailSaleResult> Handle(PostRetailSaleCommand cmd, CancellationToken ct)
    {
        // Переиспользуем уже вынесенный валидатор платежа (Sprint 1).
        if (!RetailPaymentValidator.IsSufficient(cmd.PaidCash, cmd.PaidCard, cmd.Total))
            return new PostRetailSaleResult(false,
                $"Сумма оплаты меньше итога {cmd.Total:0.##}.", "PaidCash");
        if (cmd.Lines.Count == 0)
            return new PostRetailSaleResult(false, "Пустой чек.", "lines");

        await _poster.PostAsync(cmd.SaleId, cmd.Lines, ct);
        return new PostRetailSaleResult(true, null, null);
    }
}
