using FluentValidation;
using IWS5.Core.Models.Request;
using IWS5.DatabaseAccess.Interfaces;

namespace IWS5.Services.Validators;

public class LogInCredentialsValidator : AbstractValidator<LogInCredentials>
{
    public LogInCredentialsValidator(IUserRepository userRepository)
    {
        RuleFor(x => x.UserName)
            .NotEmpty()
            .WithMessage("User name is required and should not be empty.")
            .Length(1, 255)
            .WithMessage("User name must be between 1 and 255 characters.")
            .Must(BeValidUserName)
            .WithMessage("User name contains invalid characters.");

        RuleFor(x => x.Password)
            .NotEmpty()
            .WithMessage("Password is required and should not be empty.")
            .Length(1, 1000)
            .WithMessage("Password must be between 1 and 1000 characters.")
            .Must(BeValidPassword)
            .WithMessage("Password contains invalid characters.");

        RuleFor(x => x.Domain)
            .Length(0, 255)
            .WithMessage("Domain must not exceed 255 characters.")
            .Must(BeValidDomain)
            .WithMessage("Domain contains invalid characters.")
            .When(x => !string.IsNullOrEmpty(x.Domain));
    }

    private static bool BeValidUserName(string userName)
    {
        if (string.IsNullOrWhiteSpace(userName))
            return false;

        if (userName.Contains('\0'))
            return false;

        var dangerousPatterns = new[] { "<script", "javascript:", "vbscript:", "data:" };
        var lowerUserName = userName.ToLowerInvariant();
        
        if (dangerousPatterns.Any(pattern => lowerUserName.Contains(pattern)))
            return false;

        var sqlPatterns = new[] { "'", "\"", ";", "--", "/*", "*/", "xp_", "sp_" };
        if (sqlPatterns.Any(pattern => lowerUserName.Contains(pattern)))
            return false;

        var ldapPatterns = new[] { "(", ")", "*", "\\", "/", "&", "|", "!" };
        if (ldapPatterns.Any(pattern => userName.Contains(pattern)))
            return false;

        return true;
    }

    private static bool BeValidPassword(string password)
    {
        if (string.IsNullOrWhiteSpace(password))
            return false;

        if (password.Contains('\0'))
            return false;

        var dangerousPatterns = new[] { "<script", "javascript:", "vbscript:" };
        var lowerPassword = password.ToLowerInvariant();
        
        return !dangerousPatterns.Any(pattern => lowerPassword.Contains(pattern));
    }

    private static bool BeValidDomain(string domain)
    {
        if (string.IsNullOrEmpty(domain))
            return true;

        if (domain.Contains('\0'))
            return false;

        var ldapPatterns = new[] { "(", ")", "*", "\\", "/", "&", "|", "!", "<", ">", "=" };
        if (ldapPatterns.Any(domain.Contains))
            return false;

        return domain.All(c => char.IsLetterOrDigit(c) || c == '.' || c == '-');
    }
}