#nullable enable
using Baya.Application.Contracts.Invoices;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Domain.Entities.Invoices;
using Mediator;

namespace Baya.Application.Features.Invoices.Commands.ReconcileMoadianInvoices;

/// <summary>
/// Loads the unregistered invoices (tracked), (re)submits each through <see cref="IMoadianClient"/>, and applies
/// the returned status/reference via the entity's guarded <c>ApplyMoadianResult</c>. One commit at the end. A
/// transient مودیان error leaves the invoice <c>submitted</c> so the next tick retries — it is never marked failed
/// on a transient fault.
/// </summary>
internal sealed class ReconcileMoadianInvoicesCommandHandler(
    IUnitOfWork unitOfWork,
    IMoadianClient moadianClient)
    : IRequestHandler<ReconcileMoadianInvoicesCommand, OperationResult<ReconcileMoadianResult>>
{
    private const int BatchSize = 100;

    public async ValueTask<OperationResult<ReconcileMoadianResult>> Handle(
        ReconcileMoadianInvoicesCommand request, CancellationToken cancellationToken)
    {
        var invoices = await unitOfWork.InvoiceRepository.GetUnregisteredMoadianInvoicesAsync(BatchSize, cancellationToken);

        var registered = 0;
        foreach (var invoice in invoices)
        {
            var submission = new InvoiceSubmission(
                invoice.InvoiceNumber, invoice.BookingId, invoice.GrossIrr, invoice.PlatformCommissionIrr, invoice.VatIrr);

            var result = await moadianClient.SubmitAsync(submission, cancellationToken);
            invoice.ApplyMoadianResult(result.Status, result.ReferenceNumber);

            if (result.Status == MoadianStatus.Registered)
                registered++;
        }

        if (invoices.Count > 0)
            await unitOfWork.CommitAsync();

        return OperationResult<ReconcileMoadianResult>.SuccessResult(new ReconcileMoadianResult(invoices.Count, registered));
    }
}
