using System.Text.RegularExpressions;
using Nalu.Web.Models;

namespace Nalu.Web.Services;

public enum DeterministicOutcome
{
    Unresolved,
    Rejected,
    Accepted,
    ConstraintFailed
}

public record DeterministicResult
{
    public DeterministicOutcome Outcome { get; init; }
    public string? ExtractedValue { get; init; }
    public string? Reasoning { get; init; }
}

public class DeterministicLayer
{
    public DeterministicResult Evaluate(ValidatorDefinition validator, string userInput, string language = "pt-BR")
    {
        var normalized = userInput.Trim().ToLowerInvariant().TrimEnd('.', '!', '?', ',', ';');

        // Use localized stop words when available, fall back to flat set
        var stopWords = validator.LocalizedStopWords.TryGetValue(language, out var localized)
            ? localized
            : validator.StopWords;

        if (stopWords.Contains(normalized))
        {
            return new DeterministicResult
            {
                Outcome = DeterministicOutcome.Rejected,
                Reasoning = "Usuário respondeu com saudação ou palavra de parada"
            };
        }

        // Reject patterns
        foreach (var pattern in validator.RejectPatterns)
        {
            try
            {
                if (Regex.IsMatch(normalized, pattern, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(100)))
                {
                    return new DeterministicResult
                    {
                        Outcome = DeterministicOutcome.Rejected,
                        Reasoning = "Resposta corresponde a padrão de rejeição"
                    };
                }
            }
            catch (RegexMatchTimeoutException) { /* skip on timeout */ }
        }

        // Accept patterns — capture group 1 is the extracted value.
        // Matched case-insensitively against the original (trimmed) input.
        var original = userInput.Trim().TrimEnd('.', '!', '?', ',', ';');

        foreach (var pattern in validator.AcceptPatterns)
        {
            try
            {
                var m = Regex.Match(original, pattern, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(100));
                if (!m.Success) continue;

                var extracted = m.Groups.Count > 1 && m.Groups[1].Success
                    ? m.Groups[1].Value.Trim()
                    : original;

                var violation = CheckConstraints(validator.Constraints, extracted);
                if (violation is not null)
                {
                    return new DeterministicResult
                    {
                        Outcome = DeterministicOutcome.ConstraintFailed,
                        ExtractedValue = extracted,
                        Reasoning = violation
                    };
                }

                return new DeterministicResult
                {
                    Outcome = DeterministicOutcome.Accepted,
                    ExtractedValue = extracted,
                    Reasoning = "Padrão de aceitação encontrado"
                };
            }
            catch (RegexMatchTimeoutException) { /* skip on timeout */ }
        }

        return new DeterministicResult { Outcome = DeterministicOutcome.Unresolved };
    }

    private static string? CheckConstraints(Dictionary<string, string> constraints, string value)
    {
        if (constraints.TryGetValue("min_length", out var minStr) && int.TryParse(minStr, out var min))
        {
            if (value.Length < min)
                return $"Valor muito curto (mínimo {min} caracteres)";
        }

        if (constraints.TryGetValue("max_length", out var maxStr) && int.TryParse(maxStr, out var max))
        {
            if (value.Length > max)
                return $"Valor muito longo (máximo {max} caracteres)";
        }

        if (constraints.TryGetValue("max_digits", out var maxDigStr) && int.TryParse(maxDigStr, out var maxDig))
        {
            var digitCount = value.Count(char.IsDigit);
            if (digitCount > maxDig)
                return $"Número de dígitos excede o máximo permitido ({maxDig})";
        }

        if (constraints.TryGetValue("must_have_alpha", out var alphaStr)
            && bool.TryParse(alphaStr, out var mustHaveAlpha)
            && mustHaveAlpha)
        {
            if (!value.Any(char.IsLetter))
                return "Valor deve conter letras";
        }

        if (constraints.TryGetValue("must_have_space", out var spaceStr)
            && bool.TryParse(spaceStr, out var mustHaveSpace)
            && mustHaveSpace)
        {
            if (!value.Contains(' '))
                return "Valor deve conter ao menos duas palavras";
        }

        return null;
    }
}
