using FluentAssertions;
using NSubstitute;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Products.GetById;
using SIGCM2.Domain.Entities;
using SIGCM2.Domain.Exceptions;

namespace SIGCM2.Application.Tests.Products.GetById;

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

    public GetProductByIdQueryHandlerTests()
    {
        _handler = new GetProductByIdQueryHandler(_repo);
    }

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

    [Fact]
    public async Task Handle_ExistingId_ReturnsMappedDto()
    {
        _repo.GetByIdAsync(1, Arg.Any<CancellationToken>()).Returns(AProduct(1));

        var result = await _handler.Handle(new GetProductByIdQuery(1));

        result.Id.Should().Be(1);
        result.Nombre.Should().Be("Clasificado Estándar");
        result.MedioId.Should().Be(1);
        result.ProductTypeId.Should().Be(2);
        result.BasePrice.Should().Be(100.50m);
        result.IsActive.Should().BeTrue();
    }

    [Fact]
    public async Task Handle_NotFound_ThrowsProductNotFoundException()
    {
        _repo.GetByIdAsync(99, Arg.Any<CancellationToken>()).Returns((Product?)null);

        var act = async () => await _handler.Handle(new GetProductByIdQuery(99));

        await act.Should().ThrowAsync<ProductNotFoundException>()
            .Where(e => e.ProductId == 99);
    }
}
