using FluentAssertions;
using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Audit;
using SIGCM2.Application.Products.Deactivate;
using SIGCM2.Domain.Entities;
using SIGCM2.Domain.Exceptions;
namespace SIGCM2.Application.Tests.Products.Deactivate;
///
/// PRD-002 — DeactivateProductCommandHandler tests.
///
public class DeactivateProductCommandHandlerTests
{
private readonly IProductRepository _repo = Substitute.For();
private readonly IAuditLogger _audit = Substitute.For();
private readonly FakeTimeProvider _time = new(new DateTimeOffset(2026, 4, 19, 14, 0, 0, TimeSpan.Zero));
private readonly DeactivateProductCommandHandler _handler;
public DeactivateProductCommandHandlerTests()
{
_handler = new DeactivateProductCommandHandler(_repo, _audit, _time);
}
private static Product ActiveProduct(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);
private static Product InactiveProduct(int id = 1) => new(
id: id, nombre: "Clasificado Estándar",
medioId: 1, productTypeId: 2, rubroId: null,
basePrice: 100.50m, priceDurationDays: null,
isActive: false,
fechaCreacion: new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc),
fechaModificacion: null);
// ── Not found ────────────────────────────────────────────────────────────
[Fact]
public async Task Handle_NotFound_ThrowsProductNotFoundException()
{
_repo.GetByIdAsync(99, Arg.Any()).Returns((Product?)null);
var act = async () => await _handler.Handle(new DeactivateProductCommand(99));
await act.Should().ThrowAsync()
.Where(e => e.ProductId == 99);
}
// ── Already inactive (idempotent) ─────────────────────────────────────────
[Fact]
public async Task Handle_AlreadyInactive_ReturnsDto_NoAudit_NoRepoUpdate()
{
_repo.GetByIdAsync(1, Arg.Any()).Returns(InactiveProduct());
var result = await _handler.Handle(new DeactivateProductCommand(1));
result.Id.Should().Be(1);
result.IsActive.Should().BeFalse();
await _repo.DidNotReceive().UpdateAsync(Arg.Any(), Arg.Any());
await _audit.DidNotReceive().LogAsync(
Arg.Any(), Arg.Any(), Arg.Any(),
Arg.Any