using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Invoices;
using Baya.Application.Features.Invoices.Commands.IssueInvoice;
using Baya.Domain.Entities.Invoices;
using NSubstitute;

namespace Baya.Test.Foundation.Refunds;

public class InvoiceHandlerTests
{
    private static readonly DateTimeOffset Now = new(2026, 8, 10, 10, 0, 0, TimeSpan.Zero);

    private static IssueInvoiceCommandHandler Handler(RefundsTestHost host, decimal vatRate = 0.10m)
    {
        var moadian = Substitute.For<IMoadianClient>();
        moadian.SubmitAsync(Arg.Any<InvoiceSubmission>(), Arg.Any<CancellationToken>())
            .Returns(new MoadianSubmissionResult(MoadianStatus.Pending, null));

        var storage = Substitute.For<IObjectStorage>();

        return new IssueInvoiceCommandHandler(
            host.UnitOfWork, host.Config(vatRate: vatRate), host.Clock(Now), host.Lock(), moadian, storage);
    }

    [Fact]
    public async Task Issue_computes_vat_on_commission_and_numbers_sequentially()
    {
        using var host = new RefundsTestHost();
        var (bookingA, _) = host.SeedCapturedBooking(gross: 10_000_000, commission: 1_500_000);
        var (bookingB, _) = host.SeedCapturedBooking(gross: 20_000_000, commission: 3_000_000);
        var handler = Handler(host);

        var a = await handler.Handle(new IssueInvoiceCommand(bookingA), CancellationToken.None);
        var b = await handler.Handle(new IssueInvoiceCommand(bookingB), CancellationToken.None);

        Assert.True(a.IsSuccess);
        Assert.Equal("INV-0000000001", a.Result.InvoiceNumber);
        Assert.Equal("1500000", a.Result.PlatformCommissionIrr);
        Assert.Equal("150000", a.Result.VatIrr); // 10% of the commission line, integer-only
        Assert.Equal(MoadianStatus.Pending, a.Result.MoadianStatus);
        Assert.Null(a.Result.MoadianReferenceNumber);

        // Gap-free next number, and VAT on that booking's own commission.
        Assert.Equal("INV-0000000002", b.Result.InvoiceNumber);
        Assert.Equal("300000", b.Result.VatIrr);
    }

    [Fact]
    public async Task Reissue_is_idempotent_and_returns_the_same_invoice()
    {
        using var host = new RefundsTestHost();
        var (bookingId, _) = host.SeedCapturedBooking();
        var handler = Handler(host);

        var first = await handler.Handle(new IssueInvoiceCommand(bookingId), CancellationToken.None);
        var second = await handler.Handle(new IssueInvoiceCommand(bookingId), CancellationToken.None);

        Assert.Equal(first.Result.Id, second.Result.Id);
        Assert.Equal(first.Result.InvoiceNumber, second.Result.InvoiceNumber);
    }

    [Fact]
    public async Task Zero_vat_rate_yields_zero_vat()
    {
        using var host = new RefundsTestHost();
        var (bookingId, _) = host.SeedCapturedBooking(gross: 10_000_000, commission: 1_500_000);

        var result = await Handler(host, vatRate: 0m).Handle(new IssueInvoiceCommand(bookingId), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Equal("0", result.Result.VatIrr);
    }
}
