using FluentAssertions;
using Nalu.Web.PostProcessors;
using Nalu.Web.Services;
using Xunit;

namespace Nalu.Tests;

// ── ValidateCpfDigit ──────────────────────────────────────────────────────────

public class ValidateCpfDigitTests
{
    private readonly ValidateCpfDigit _sut = new();

    [Theory]
    [InlineData("529.982.247-25", "529.982.247-25")] // valid CPF
    [InlineData("52998224725",    "529.982.247-25")] // no formatting
    [InlineData("529 982 247 25", "529.982.247-25")] // spaces
    public void ValidCpf_ReturnsFormattedValue(string input, string expected)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeTrue();
        result.Value.Should().Be(expected);
    }

    [Theory]
    [InlineData("111.111.111-11")] // all same digit
    [InlineData("000.000.000-00")]
    [InlineData("123.456.789-00")] // wrong check digits
    [InlineData("1234567890")]     // too few digits
    [InlineData("123456789012")]   // too many digits
    public void InvalidCpf_ReturnsInvalid(string input)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeFalse();
        result.InvalidReason.Should().NotBeNullOrEmpty();
    }
}

// ── FormatPhone ───────────────────────────────────────────────────────────────

public class FormatPhoneTests
{
    private readonly FormatPhone _sut = new();

    [Theory]
    [InlineData("11999998888",       "(11) 99999-8888")] // mobile, no formatting
    [InlineData("(11) 99999-8888",   "(11) 99999-8888")] // already formatted
    [InlineData("+55 11 99999-8888", "(11) 99999-8888")] // with country code
    [InlineData("1134567890",        "(11) 3456-7890")]  // landline
    public void ValidPhone_ReturnsFormatted(string input, string expected)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeTrue();
        result.Value.Should().Be(expected);
    }

    [Theory]
    [InlineData("9999")]            // too short
    [InlineData("999999999999999")] // too long
    [InlineData("1190909090909")]   // 13 digits — no valid Brazilian format
    [InlineData("23999998888")]     // invalid DDD 23
    [InlineData("36999998888")]     // invalid DDD 36
    [InlineData("52999998888")]     // invalid DDD 52
    public void InvalidPhone_ReturnsInvalid(string input)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeFalse();
    }
}

// ── FormatCep ─────────────────────────────────────────────────────────────────

public class FormatCepTests
{
    private readonly FormatCep _sut = new();

    [Theory]
    [InlineData("01001000",  "01001-000")]
    [InlineData("01001-000", "01001-000")]
    [InlineData("04538133",  "04538-133")]
    public void ValidCep_ReturnsFormatted(string input, string expected)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeTrue();
        result.Value.Should().Be(expected);
    }

    [Theory]
    [InlineData("0000000")]   // 7 digits
    [InlineData("000000000")] // 9 digits
    [InlineData("00000000")]  // all zeros
    public void InvalidCep_ReturnsInvalid(string input)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeFalse();
    }
}

// ── CorrectEmailTypos ─────────────────────────────────────────────────────────

public class CorrectEmailTyposTests
{
    private readonly CorrectEmailTypos _sut = new();

    [Theory]
    [InlineData("user@gamil.com",    "user@gmail.com",   "user@gamil.com")]
    [InlineData("user@gmaill.com",   "user@gmail.com",   "user@gmaill.com")]
    [InlineData("user@hotmal.com",   "user@hotmail.com", "user@hotmal.com")]
    [InlineData("user@outlok.com",   "user@outlook.com", "user@outlok.com")]
    [InlineData("user@yaho.com",     "user@yahoo.com",   "user@yaho.com")]
    public void TypoDomain_ReturnsCorrected(string input, string expectedValue, string expectedOriginal)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeTrue();
        result.WasCorrected.Should().BeTrue();
        result.Value.Should().Be(expectedValue);
        result.OriginalValue.Should().Be(expectedOriginal);
    }

    [Theory]
    [InlineData("user@gmail.com")]
    [InlineData("user@hotmail.com")]
    [InlineData("user@company.com.br")]
    public void CorrectDomain_ReturnsOk_NotCorrected(string input)
    {
        var result = _sut.Process(input);

        result.IsValid.Should().BeTrue();
        result.WasCorrected.Should().BeFalse();
    }
}

// ── DeterministicLayer — new validators ───────────────────────────────────────

public class CpfDeterministicTests
{
    private readonly DeterministicLayer _layer = new();

    [Fact]
    public void CpfPattern_ExtractsDigits()
    {
        var validator = ValidatorLoader.ParseFromContent("validate_cpf",
            System.IO.File.ReadAllText("../../../../../src/Nalu.Api/Validators/validate_cpf.md"));

        var result = _layer.Evaluate(validator, "123.456.789-09");

        result.Outcome.Should().Be(DeterministicOutcome.Accepted);
        result.ExtractedValue.Should().Be("123.456.789-09"); // raw match; postprocessor strips punctuation
    }

    [Fact]
    public void CpfEvasive_ReturnsRejected()
    {
        var validator = ValidatorLoader.ParseFromContent("validate_cpf",
            System.IO.File.ReadAllText("../../../../../src/Nalu.Api/Validators/validate_cpf.md"));

        var result = _layer.Evaluate(validator, "não lembro");

        result.Outcome.Should().Be(DeterministicOutcome.Rejected);
    }
}
