using System.Text.RegularExpressions;
namespace Foxnouns.Backend.Utils;
/// 
/// Static methods for validating user input (mostly making sure it's not too short or too long)
/// 
public static class ValidationUtils
{
    private static readonly Regex UsernameRegex = new("^[\\w-.]{2,40}$", RegexOptions.IgnoreCase);
    private static readonly Regex MemberRegex =
        new("^[^@\\?!#/\\\\[\\]\"\\{\\}'$%&()+<=>^|~`,\\*]{1,100}$", RegexOptions.IgnoreCase);
    private static readonly string[] InvalidUsernames =
    [
        "..",
        "admin",
        "administrator",
        "mod",
        "moderator",
        "api",
        "page",
        "pronouns",
        "settings",
        "pronouns.cc",
        "pronounscc"
    ];
    private static readonly string[] InvalidMemberNames =
    [
        // these break routing outright
        ".",
        "..",
        // the user edit page lives at `/@{username}/edit`, so a member named "edit" would be inaccessible
        "edit"
    ];
    public static ValidationError? ValidateUsername(string username)
    {
        if (!UsernameRegex.IsMatch(username))
            return username.Length switch
            {
                < 2 => ValidationError.LengthError("Username is too short", 2, 40, username.Length),
                > 40 => ValidationError.LengthError("Username is too long", 2, 40, username.Length),
                _ => ValidationError.GenericValidationError(
                    "Username is invalid, can only contain alphanumeric characters, dashes, underscores, and periods",
                    username)
            };
        if (InvalidUsernames.Any(u => string.Equals(u, username, StringComparison.InvariantCultureIgnoreCase)))
            return ValidationError.GenericValidationError("Username is not allowed", username);
        return null;
    }
    public static ValidationError? ValidateMemberName(string memberName)
    {
        if (!UsernameRegex.IsMatch(memberName))
            return memberName.Length switch
            {
                < 2 => ValidationError.LengthError("Name is too short", 1, 100, memberName.Length),
                > 40 => ValidationError.LengthError("Name is too long", 1, 100, memberName.Length),
                _ => ValidationError.GenericValidationError(
                    "Member name cannot contain any of the following: " +
                    " @, ?, !, #, /, \\, [, ], \", ', $, %, &, (, ), {, }, +, <, =, >, ^, |, ~, `, , " +
                    "and cannot be one or two periods",
                    memberName)
            };
        if (InvalidMemberNames.Any(u => string.Equals(u, memberName, StringComparison.InvariantCultureIgnoreCase)))
            return ValidationError.GenericValidationError("Name is not allowed", memberName);
        return null;
    }
    public static void Validate(IEnumerable<(string, ValidationError?)> errors)
    {
        errors = errors.Where(e => e.Item2 != null).ToList();
        if (!errors.Any()) return;
        var errorDict = new Dictionary>();
        foreach (var error in errors)
        {
            if (errorDict.TryGetValue(error.Item1, out var value)) errorDict[error.Item1] = value.Append(error.Item2!);
            errorDict.Add(error.Item1, [error.Item2!]);
        }
        throw new ApiError.BadRequest("Error validating input", errorDict);
    }
    public static ValidationError? ValidateDisplayName(string? displayName)
    {
        return displayName?.Length switch
        {
            0 => ValidationError.LengthError("Display name is too short", 1, 100, displayName.Length),
            > 100 => ValidationError.LengthError("Display name is too long", 1, 100, displayName.Length),
            _ => null
        };
    }
    public static ValidationError? ValidateBio(string? bio)
    {
        return bio?.Length switch
        {
            0 => ValidationError.LengthError("Bio is too short", 1, 1024, bio.Length),
            > 1024 => ValidationError.LengthError("Bio is too long", 1, 1024, bio.Length),
            _ => null
        };
    }
    public static ValidationError? ValidateAvatar(string? avatar)
    {
        return avatar?.Length switch
        {
            0 => ValidationError.GenericValidationError("Avatar cannot be empty", null),
            > 1_500_00 => ValidationError.GenericValidationError("Avatar is too large", null),
            _ => null
        };
    }
}