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

namespace Nalu.Tests;

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

    private static ValidatorDefinition NameValidator() => new ValidatorDefinition
    {
        Id = "validate_full_name",
        StopWords = ["bom dia", "boa tarde", "boa noite", "olá", "oi"],
        RejectPatterns =
        [
            @"^(não|nao|sei la|sei lá|tanto faz)$",
            @"^\d+$"
        ],
        AcceptPatterns =
        [
            @"^meu nome é\s+(.+)$",
            @"^me chamo\s+(.+)$"
        ],
        Constraints = new Dictionary<string, string>
        {
            { "min_length", "2" },
            { "must_have_alpha", "true" },
            { "max_length", "120" }
        }
    };

    // ── Stop words ────────────────────────────────────────────────────────────

    [Theory]
    [InlineData("Bom dia")]
    [InlineData("bom dia")]
    [InlineData("Bom dia!")]
    [InlineData("Oi")]
    [InlineData("olá")]
    public void StopWord_ReturnsRejected(string input)
    {
        var result = _layer.Evaluate(NameValidator(), input);

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

    // ── Reject patterns ───────────────────────────────────────────────────────

    [Theory]
    [InlineData("não")]
    [InlineData("sei la")]
    [InlineData("tanto faz")]
    [InlineData("12345")]
    public void RejectPattern_ReturnsRejected(string input)
    {
        var result = _layer.Evaluate(NameValidator(), input);

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

    // ── Accept patterns ───────────────────────────────────────────────────────

    [Theory]
    [InlineData("meu nome é João Silva", "João Silva")]
    [InlineData("Meu nome é Maria", "Maria")]
    [InlineData("me chamo Pedro", "Pedro")]
    public void AcceptPattern_ReturnsAcceptedWithCapturedGroup(string input, string expectedValue)
    {
        var result = _layer.Evaluate(NameValidator(), input);

        result.Outcome.Should().Be(DeterministicOutcome.Accepted);
        result.ExtractedValue.Should().Be(expectedValue);
    }

    // ── Unresolved ────────────────────────────────────────────────────────────

    [Theory]
    [InlineData("Carlos Alberto Ferreira")]
    [InlineData("Ana")]
    public void FreeText_ReturnsUnresolved(string input)
    {
        var result = _layer.Evaluate(NameValidator(), input);

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

    // ── Constraints ───────────────────────────────────────────────────────────

    [Fact]
    public void AcceptPattern_WhenValueTooShort_ReturnsConstraintFailed()
    {
        var validator = NameValidator();
        validator.Constraints["min_length"] = "5";

        var result = _layer.Evaluate(validator, "meu nome é Al");

        result.Outcome.Should().Be(DeterministicOutcome.ConstraintFailed);
        result.Reasoning.Should().Contain("mínimo");
    }

    [Fact]
    public void AcceptPattern_WhenValueHasNoLetters_ReturnsConstraintFailed()
    {
        var result = _layer.Evaluate(NameValidator(), "meu nome é 999");

        result.Outcome.Should().Be(DeterministicOutcome.ConstraintFailed);
        result.Reasoning.Should().Contain("letras");
    }

    [Fact]
    public void AcceptPattern_WhenValueTooLong_ReturnsConstraintFailed()
    {
        var longName = new string('A', 121);
        var result = _layer.Evaluate(NameValidator(), $"meu nome é {longName}");

        result.Outcome.Should().Be(DeterministicOutcome.ConstraintFailed);
        result.Reasoning.Should().Contain("máximo");
    }

    // ── No patterns configured ────────────────────────────────────────────────

    [Fact]
    public void EmptyValidator_AlwaysUnresolved()
    {
        var validator = new ValidatorDefinition { Id = "empty" };
        var result = _layer.Evaluate(validator, "qualquer coisa");

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