using NSubstitute;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Audit;
using SIGCM2.Application.IngresosBrutos.Create;
using SIGCM2.Domain.Fiscal;
using IibbEntity = SIGCM2.Domain.Entities.IngresosBrutos;

namespace SIGCM2.Application.Tests.IngresosBrutos.Create;

public class CreateIngresosBrutosCommandHandlerTests
{
    private readonly IIngresosBrutosRepository _repo = Substitute.For<IIngresosBrutosRepository>();
    private readonly IAuditLogger _audit = Substitute.For<IAuditLogger>();
    private readonly CreateIngresosBrutosCommandHandler _handler;

    private static CreateIngresosBrutosCommand ValidCommand() => new(
        Provincia: ProvinciaArgentina.BuenosAires,
        Descripcion: "IIBB Buenos Aires",
        Alicuota: 3.5m,
        VigenciaDesde: new DateOnly(2024, 1, 1));

    public CreateIngresosBrutosCommandHandlerTests()
    {
        _handler = new CreateIngresosBrutosCommandHandler(_repo, _audit, TimeProvider.System);
        _repo.InsertAsync(Arg.Any<IibbEntity>(), Arg.Any<CancellationToken>()).Returns(55);
    }

    [Fact]
    public async Task Handle_HappyPath_ReturnsDtoWithIdFromRepository()
    {
        var result = await _handler.Handle(ValidCommand());

        Assert.Equal(55, result.Id);
    }

    [Fact]
    public async Task Handle_HappyPath_DtoContainsCorrectFields()
    {
        var result = await _handler.Handle(ValidCommand());

        Assert.Equal(ProvinciaArgentina.BuenosAires, result.Provincia);
        Assert.Equal(3.5m, result.Alicuota);
        Assert.True(result.Activo);
    }

    [Fact]
    public async Task Handle_HappyPath_CallsAuditWithCreateAction()
    {
        await _handler.Handle(ValidCommand());

        await _audit.Received(1).LogAsync(
            action: "ingresos_brutos.create",
            targetType: "IngresosBrutos",
            targetId: "55",
            metadata: Arg.Any<object?>(),
            ct: Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task Handle_AuditLoggerThrows_ExceptionBubblesUp()
    {
        _audit.LogAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(),
                        Arg.Any<object?>(), Arg.Any<CancellationToken>())
              .Returns(Task.FromException(new InvalidOperationException("audit fail")));

        await Assert.ThrowsAsync<InvalidOperationException>(
            () => _handler.Handle(ValidCommand()));
    }

    // ── triangulation: zero alicuota ─────────────────────────────────────────

    [Fact]
    public async Task Handle_WithZeroAlicuota_ReturnsDtoWithCorrectAlicuota()
    {
        var cmd = new CreateIngresosBrutosCommand(
            Provincia: ProvinciaArgentina.CiudadAutonomaDeBuenosAires,
            Descripcion: "IIBB CABA",
            Alicuota: 0m,
            VigenciaDesde: new DateOnly(2024, 1, 1));

        var result = await _handler.Handle(cmd);

        Assert.Equal(0m, result.Alicuota);
        Assert.Equal(ProvinciaArgentina.CiudadAutonomaDeBuenosAires, result.Provincia);
    }
}
