using FluentAssertions;
using NSubstitute;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Common;
using SIGCM2.Application.Products.List;
using SIGCM2.Domain.Entities;

namespace SIGCM2.Application.Tests.Products.List;

/// <summary>
/// PRD-002 — ListProductsQueryHandler tests.
/// </summary>
public class ListProductsQueryHandlerTests
{
    private readonly IProductRepository _repo = Substitute.For<IProductRepository>();
    private readonly ListProductsQueryHandler _handler;

    public ListProductsQueryHandlerTests()
    {
        _repo.GetPagedAsync(Arg.Any<ProductsQuery>(), Arg.Any<CancellationToken>())
             .Returns(new PagedResult<Product>([], 1, 20, 0));
        _handler = new ListProductsQueryHandler(_repo);
    }

    private static Product AProduct(int id = 1) => new(
        id: id,
        nombre: "Clasificado",
        medioId: 1,
        productTypeId: 2,
        rubroId: null,
        basePrice: 50m,
        priceDurationDays: null,
        isActive: true,
        fechaCreacion: new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc),
        fechaModificacion: null);

    [Fact]
    public async Task Handle_EmptyPage_ReturnsPaged_WithZeroTotal()
    {
        var result = await _handler.Handle(new ListProductsQuery());

        result.Total.Should().Be(0);
        result.Items.Should().BeEmpty();
    }

    [Fact]
    public async Task Handle_WithItems_ReturnsMappedListItemDtos()
    {
        _repo.GetPagedAsync(Arg.Any<ProductsQuery>(), Arg.Any<CancellationToken>())
             .Returns(new PagedResult<Product>([AProduct(1), AProduct(2)], 1, 20, 2));

        var result = await _handler.Handle(new ListProductsQuery());

        result.Items.Should().HaveCount(2);
        result.Items[0].Id.Should().Be(1);
        result.Items[1].Id.Should().Be(2);
    }

    [Fact]
    public async Task Handle_PageNormalization_ClampsPageSizeTo100()
    {
        await _handler.Handle(new ListProductsQuery(Page: 1, PageSize: 200));

        await _repo.Received(1).GetPagedAsync(
            Arg.Is<ProductsQuery>(q => q.PageSize == 100),
            Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task Handle_PageBelowOne_NormalizesToOne()
    {
        await _handler.Handle(new ListProductsQuery(Page: -1));

        await _repo.Received(1).GetPagedAsync(
            Arg.Is<ProductsQuery>(q => q.Page == 1),
            Arg.Any<CancellationToken>());
    }

    [Fact]
    public async Task Handle_PassesFiltersToRepo()
    {
        await _handler.Handle(new ListProductsQuery(MedioId: 5, ProductTypeId: 3, RubroId: 7));

        await _repo.Received(1).GetPagedAsync(
            Arg.Is<ProductsQuery>(q => q.MedioId == 5 && q.ProductTypeId == 3 && q.RubroId == 7),
            Arg.Any<CancellationToken>());
    }
}
