using FluentValidation.TestHelper;
using SIGCM2.Application.Products.Create;
using SIGCM2.Application.Products.Update;

namespace SIGCM2.Application.Tests.Products.Validators;

/// <summary>
/// PRD-002 — Validator tests for CreateProductCommand and UpdateProductCommand.
/// </summary>
public class ProductValidatorsTests
{
    private readonly CreateProductCommandValidator _createValidator = new();
    private readonly UpdateProductCommandValidator _updateValidator = new();

    // ── Create: Nombre ────────────────────────────────────────────────────────

    [Fact]
    public void Create_NombreEmpty_FailsValidation()
    {
        var cmd = ValidCreate() with { Nombre = "" };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Nombre);
    }

    [Fact]
    public void Create_NombreWhitespace_FailsValidation()
    {
        var cmd = ValidCreate() with { Nombre = "   " };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Nombre);
    }

    [Fact]
    public void Create_NombreOver300Chars_FailsValidation()
    {
        var cmd = ValidCreate() with { Nombre = new string('X', 301) };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Nombre);
    }

    // ── Create: MedioId / ProductTypeId ───────────────────────────────────────

    [Fact]
    public void Create_MedioIdZero_FailsValidation()
    {
        var cmd = ValidCreate() with { MedioId = 0 };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.MedioId);
    }

    [Fact]
    public void Create_ProductTypeIdZero_FailsValidation()
    {
        var cmd = ValidCreate() with { ProductTypeId = 0 };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.ProductTypeId);
    }

    // ── Create: BasePrice ─────────────────────────────────────────────────────

    [Fact]
    public void Create_NegativeBasePrice_FailsValidation()
    {
        var cmd = ValidCreate() with { BasePrice = -0.01m };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.BasePrice);
    }

    [Fact]
    public void Create_ZeroBasePrice_Passes()
    {
        var cmd = ValidCreate() with { BasePrice = 0m };
        _createValidator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.BasePrice);
    }

    // ── Create: PriceDurationDays ──────────────────────────────────────────────

    [Fact]
    public void Create_PriceDurationDaysZero_FailsValidation()
    {
        var cmd = ValidCreate() with { PriceDurationDays = 0 };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.PriceDurationDays);
    }

    [Fact]
    public void Create_PriceDurationDaysNegative_FailsValidation()
    {
        var cmd = ValidCreate() with { PriceDurationDays = -1 };
        _createValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.PriceDurationDays);
    }

    [Fact]
    public void Create_PriceDurationDaysNull_Passes()
    {
        var cmd = ValidCreate() with { PriceDurationDays = null };
        _createValidator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.PriceDurationDays);
    }

    // ── Create: valid ─────────────────────────────────────────────────────────

    [Fact]
    public void Create_ValidCommand_Passes()
    {
        _createValidator.TestValidate(ValidCreate()).ShouldNotHaveAnyValidationErrors();
    }

    // ── Update: Id must be > 0 ────────────────────────────────────────────────

    [Fact]
    public void Update_IdZero_FailsValidation()
    {
        var cmd = ValidUpdate() with { Id = 0 };
        _updateValidator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Id);
    }

    [Fact]
    public void Update_ValidCommand_Passes()
    {
        _updateValidator.TestValidate(ValidUpdate()).ShouldNotHaveAnyValidationErrors();
    }

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

    private static CreateProductCommand ValidCreate() => new(
        Nombre: "Clasificado Estándar",
        MedioId: 1,
        ProductTypeId: 2,
        RubroId: null,
        BasePrice: 100.50m,
        PriceDurationDays: null);

    private static UpdateProductCommand ValidUpdate() => new(
        Id: 1,
        Nombre: "Clasificado Estándar",
        RubroId: null,
        BasePrice: 100.50m,
        PriceDurationDays: null);
}
