namespace Application.Students.Commands;

using System.Text.RegularExpressions;
using Domain.Ports.Repositories;
using FluentValidation;

public partial class CreateStudentValidator : AbstractValidator<CreateStudentCommand>
{
    [GeneratedRegex(@"^[\p{L}\s\-'\.]+$", RegexOptions.Compiled)]
    private static partial Regex SafeNamePattern();

    [GeneratedRegex(@"<[^>]*>|javascript:|on\w+=", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
    private static partial Regex DangerousPattern();

    public CreateStudentValidator(IStudentRepository studentRepository)
    {
        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("Name is required")
            .MinimumLength(3).WithMessage("Name must be at least 3 characters")
            .MaximumLength(100).WithMessage("Name must not exceed 100 characters")
            .Matches(SafeNamePattern()).WithMessage("Name contains invalid characters")
            .Must(NotContainDangerousContent).WithMessage("Name contains prohibited content");

        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("Email is required")
            .MaximumLength(254).WithMessage("Email must not exceed 254 characters")
            .EmailAddress().WithMessage("Invalid email format")
            .Must(NotContainDangerousContent).WithMessage("Email contains prohibited content")
            .MustAsync(async (email, ct) =>
                !await studentRepository.EmailExistsAsync(email, null, ct))
            .WithMessage("Email already exists");
    }

    private static bool NotContainDangerousContent(string? value) =>
        string.IsNullOrEmpty(value) || !DangerousPattern().IsMatch(value);
}

public partial class UpdateStudentValidator : AbstractValidator<UpdateStudentCommand>
{
    [GeneratedRegex(@"^[\p{L}\s\-'\.]+$", RegexOptions.Compiled)]
    private static partial Regex SafeNamePattern();

    [GeneratedRegex(@"<[^>]*>|javascript:|on\w+=", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
    private static partial Regex DangerousPattern();

    public UpdateStudentValidator(IStudentRepository studentRepository)
    {
        RuleFor(x => x.Id)
            .GreaterThan(0).WithMessage("Invalid student ID");

        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("Name is required")
            .MinimumLength(3).WithMessage("Name must be at least 3 characters")
            .MaximumLength(100).WithMessage("Name must not exceed 100 characters")
            .Matches(SafeNamePattern()).WithMessage("Name contains invalid characters")
            .Must(NotContainDangerousContent).WithMessage("Name contains prohibited content");

        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("Email is required")
            .MaximumLength(254).WithMessage("Email must not exceed 254 characters")
            .EmailAddress().WithMessage("Invalid email format")
            .Must(NotContainDangerousContent).WithMessage("Email contains prohibited content")
            .MustAsync(async (command, email, ct) =>
                !await studentRepository.EmailExistsAsync(email, command.Id, ct))
            .WithMessage("Email already exists");
    }

    private static bool NotContainDangerousContent(string? value) =>
        string.IsNullOrEmpty(value) || !DangerousPattern().IsMatch(value);
}
