using MediatR;

namespace foodmarket.Application.Purchases.Commands;

/// <summary>CQRS-образец №2 (TD-1): команда создания приёмки (Draft).
/// Handler принимает input + контракт <see cref="ISupplyWriter"/> и делегирует
/// фактическое сохранение — handler не зависит от EF напрямую, что
/// упрощает unit-тестирование.
///
/// Покрывает только Draft-создание; Posting остаётся в контроллере (где
/// stock-логика и serializable-транзакция). Это сознательное «partial»:
/// показываем паттерн, не переписываем всё.</summary>
public record CreateSupplyCommand(
    Guid SupplierId, Guid StoreId, Guid CurrencyId,
    DateTime Date, string? Notes,
    IReadOnlyList<CreateSupplyLine> Lines) : IRequest<CreateSupplyResult>;

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

public record CreateSupplyResult(Guid Id, string Number, decimal Total);

/// <summary>Абстракция над персистентностью: позволяет тестировать handler
/// без EF/Postgres (in-memory implementation в тестах).</summary>
public interface ISupplyWriter
{
    Task<string> NextNumberAsync(int year, CancellationToken ct);
    Task<Guid> CreateAsync(Guid supplierId, Guid storeId, Guid currencyId,
        DateTime date, string? notes, string number,
        IReadOnlyList<CreateSupplyLine> lines, decimal total,
        CancellationToken ct);
}

public sealed class CreateSupplyHandler : IRequestHandler<CreateSupplyCommand, CreateSupplyResult>
{
    private readonly ISupplyWriter _writer;
    public CreateSupplyHandler(ISupplyWriter writer) => _writer = writer;

    public async Task<CreateSupplyResult> Handle(CreateSupplyCommand cmd, CancellationToken ct)
    {
        // Бизнес-правила: суммирование, генерация номера, делегирование
        // персистентности абстракции.
        var total = cmd.Lines.Sum(l => l.Quantity * l.UnitPrice);
        var number = await _writer.NextNumberAsync(cmd.Date.Year, ct);
        var id = await _writer.CreateAsync(
            cmd.SupplierId, cmd.StoreId, cmd.CurrencyId,
            cmd.Date, cmd.Notes, number, cmd.Lines, total, ct);
        return new CreateSupplyResult(id, number, total);
    }
}
