using FluentAssertions;
using SIGCM2.Domain.Exceptions;

namespace SIGCM2.Application.Tests.Domain;

/// <summary>
/// PRD-003 — Domain unit tests for ProductPrice-related exceptions.
/// Verifies constructor props, message content, and DomainException inheritance.
/// </summary>
public class ProductPriceExceptionTests
{
    // ── ProductPriceForwardOnlyException ─────────────────────────────────────

    [Fact]
    public void ProductPriceForwardOnlyException_SetsProperties()
    {
        var newPvf    = new DateOnly(2026, 3, 1);
        var activePvf = new DateOnly(2026, 4, 1);

        var ex = new ProductPriceForwardOnlyException(productId: 42, newPvf, activePvf);

        ex.ProductId.Should().Be(42);
        ex.NewPriceValidFrom.Should().Be(newPvf);
        ex.ActivePriceValidFrom.Should().Be(activePvf);
    }

    [Fact]
    public void ProductPriceForwardOnlyException_MessageContainsKeyDates()
    {
        var newPvf    = new DateOnly(2026, 3, 1);
        var activePvf = new DateOnly(2026, 4, 1);

        var ex = new ProductPriceForwardOnlyException(productId: 5, newPvf, activePvf);

        ex.Message.Should().Contain("2026-03-01");
        ex.Message.Should().Contain("2026-04-01");
    }

    [Fact]
    public void ProductPriceForwardOnlyException_InheritsFromDomainException()
    {
        var ex = new ProductPriceForwardOnlyException(
            productId: 1,
            newPriceValidFrom: new DateOnly(2026, 1, 1),
            activePriceValidFrom: new DateOnly(2026, 2, 1));

        ex.Should().BeAssignableTo<DomainException>();
    }

    // ── ProductPriceInvalidException ─────────────────────────────────────────

    [Fact]
    public void ProductPriceInvalidException_SetsProperties()
    {
        var ex = new ProductPriceInvalidException(field: "Price", reason: "must be > 0");

        ex.Field.Should().Be("Price");
        ex.Reason.Should().Be("must be > 0");
    }

    [Fact]
    public void ProductPriceInvalidException_MessageContainsFieldAndReason()
    {
        var ex = new ProductPriceInvalidException(field: "Price", reason: "must be > 0");

        ex.Message.Should().Contain("Price");
        ex.Message.Should().Contain("must be > 0");
    }

    [Fact]
    public void ProductPriceInvalidException_InheritsFromDomainException()
    {
        var ex = new ProductPriceInvalidException("Price", "invalid");

        ex.Should().BeAssignableTo<DomainException>();
    }

    // ── ProductSinPrecioActivoException ──────────────────────────────────────

    [Fact]
    public void ProductSinPrecioActivoException_SetsProperties()
    {
        var date = new DateOnly(2026, 4, 19);

        var ex = new ProductSinPrecioActivoException(productId: 99, date);

        ex.ProductId.Should().Be(99);
        ex.Date.Should().Be(date);
    }

    [Fact]
    public void ProductSinPrecioActivoException_MessageContainsProductIdAndDate()
    {
        var date = new DateOnly(2026, 4, 19);

        var ex = new ProductSinPrecioActivoException(productId: 99, date);

        ex.Message.Should().Contain("99");
        ex.Message.Should().Contain("2026-04-19");
    }

    [Fact]
    public void ProductSinPrecioActivoException_InheritsFromDomainException()
    {
        var ex = new ProductSinPrecioActivoException(1, new DateOnly(2026, 4, 1));

        ex.Should().BeAssignableTo<DomainException>();
    }

    // ── ProductNotFoundException — already exists, verify it works ────────────

    [Fact]
    public void ProductNotFoundException_SetsProductIdAndMessage()
    {
        var ex = new ProductNotFoundException(77);

        ex.ProductId.Should().Be(77);
        ex.Message.Should().Contain("77");
    }

    [Fact]
    public void ProductNotFoundException_InheritsFromDomainException()
    {
        var ex = new ProductNotFoundException(1);

        ex.Should().BeAssignableTo<DomainException>();
    }
}
