using FluentValidation.TestHelper;
using Microsoft.Extensions.Time.Testing;
using SIGCM2.Application.Products.Prices.AddPrice;

namespace SIGCM2.Application.Tests.Products.Prices;

/// <summary>
/// PRD-003 — Validator tests for AddProductPriceCommand.
/// FakeTimeProvider fija hoy = 2026-04-19 (UTC-3, ART).
/// Covers: §REQ-3.1 (price > 0), §REQ-3.2 (priceValidFrom >= hoy_AR), productId > 0.
/// </summary>
public class AddProductPriceCommandValidatorTests
{
    // Hoy en ART (UTC-3): 2026-04-19T12:00:00 UTC → 2026-04-19T09:00:00 ART
    // FakeTimeProvider se crea con un DateTimeOffset UTC; GetArgentinaToday() convierte a ART.
    private readonly FakeTimeProvider _time = new(new DateTimeOffset(2026, 4, 19, 12, 0, 0, TimeSpan.Zero));
    private readonly AddProductPriceCommandValidator _validator;

    public AddProductPriceCommandValidatorTests()
    {
        _validator = new AddProductPriceCommandValidator(_time);
    }

    private static readonly DateOnly Today = new(2026, 4, 19);
    private static readonly DateOnly Yesterday = new(2026, 4, 18);
    private static readonly DateOnly Tomorrow = new(2026, 4, 20);

    // ── ProductId ────────────────────────────────────────────────────────────────

    [Fact]
    public void ProductId_Zero_FailsValidation()
    {
        var cmd = ValidCmd() with { ProductId = 0 };
        _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.ProductId);
    }

    [Fact]
    public void ProductId_Negative_FailsValidation()
    {
        var cmd = ValidCmd() with { ProductId = -1 };
        _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.ProductId);
    }

    [Fact]
    public void ProductId_Positive_Passes()
    {
        var cmd = ValidCmd() with { ProductId = 1 };
        _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.ProductId);
    }

    // ── Price ────────────────────────────────────────────────────────────────────

    [Fact]
    public void Price_Zero_FailsValidation()
    {
        // §REQ-3.1 — price debe ser > 0
        var cmd = ValidCmd() with { Price = 0m };
        _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Price);
    }

    [Fact]
    public void Price_Negative_FailsValidation()
    {
        var cmd = ValidCmd() with { Price = -0.01m };
        _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Price);
    }

    [Fact]
    public void Price_Positive_Passes()
    {
        var cmd = ValidCmd() with { Price = 100m };
        _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.Price);
    }

    // ── PriceValidFrom ────────────────────────────────────────────────────────────

    [Fact]
    public void PriceValidFrom_InPast_FailsValidation()
    {
        // §REQ-3.2 — fecha pasada → invalid
        var cmd = ValidCmd() with { PriceValidFrom = Yesterday };
        _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.PriceValidFrom);
    }

    [Fact]
    public void PriceValidFrom_Today_Passes()
    {
        // Hoy mismo debe ser válido (inclusive lower bound)
        var cmd = ValidCmd() with { PriceValidFrom = Today };
        _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.PriceValidFrom);
    }

    [Fact]
    public void PriceValidFrom_Future_Passes()
    {
        // §OQ-C — fechas futuras permitidas (programar próximo precio)
        var cmd = ValidCmd() with { PriceValidFrom = Tomorrow };
        _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.PriceValidFrom);
    }

    // ── Happy path ────────────────────────────────────────────────────────────────

    [Fact]
    public void ValidCommand_PassesAllRules()
    {
        _validator.TestValidate(ValidCmd()).ShouldNotHaveAnyValidationErrors();
    }

    // ── Helpers ───────────────────────────────────────────────────────────────────

    private static AddProductPriceCommand ValidCmd() => new(
        ProductId: 1,
        Price: 150.00m,
        PriceValidFrom: Today);
}
