using System.Text.RegularExpressions;

namespace Guestlist;

public static partial class InputRules
{
    public const int UsernameMaxLength = 40;
    public const int DisplayNameMaxLength = 80;
    public const int PasswordMinLength = 8;
    public const int PasswordMaxLength = 200;
    public const int GuestNameMaxLength = 120;
    public const int GuestNotesMaxLength = 500;
    public const int AccessCodeMinLength = 6;
    public const int AccessCodeMaxLength = 120;

    public static string NormalizeUsername(string username)
    {
        var normalizedUsername = username.Trim().ToLowerInvariant();

        if (string.IsNullOrWhiteSpace(normalizedUsername))
        {
            throw new InvalidOperationException("Provide a username.");
        }

        if (normalizedUsername.Length > UsernameMaxLength)
        {
            throw new InvalidOperationException($"Username must be {UsernameMaxLength} characters or less.");
        }

        if (!UsernameRegex().IsMatch(normalizedUsername))
        {
            throw new InvalidOperationException("Username may only contain letters, numbers, dots, dashes and underscores.");
        }

        return normalizedUsername;
    }

    public static string CleanRequiredText(string value, string fieldName, int maxLength)
    {
        var cleanedValue = value.Trim();

        if (string.IsNullOrWhiteSpace(cleanedValue))
        {
            throw new InvalidOperationException($"Provide {fieldName}.");
        }

        if (cleanedValue.Length > maxLength)
        {
            throw new InvalidOperationException($"{fieldName} must be {maxLength} characters or less.");
        }

        return cleanedValue;
    }

    public static string? CleanOptionalText(string? value, string fieldName, int maxLength)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return null;
        }

        var cleanedValue = value.Trim();

        if (cleanedValue.Length > maxLength)
        {
            throw new InvalidOperationException($"{fieldName} must be {maxLength} characters or less.");
        }

        return cleanedValue;
    }

    public static void ValidatePassword(string password)
    {
        if (string.IsNullOrWhiteSpace(password))
        {
            throw new InvalidOperationException("Provide a password.");
        }

        if (password.Length < PasswordMinLength)
        {
            throw new InvalidOperationException($"Password must be at least {PasswordMinLength} characters long.");
        }

        if (password.Length > PasswordMaxLength)
        {
            throw new InvalidOperationException($"Password must be {PasswordMaxLength} characters or less.");
        }
    }

    public static string CleanAccessCode(string code)
    {
        var cleanedCode = code.Trim();

        if (string.IsNullOrWhiteSpace(cleanedCode))
        {
            throw new InvalidOperationException("Provide a guest access code.");
        }

        if (cleanedCode.Length < AccessCodeMinLength)
        {
            throw new InvalidOperationException($"Guest access code must be at least {AccessCodeMinLength} characters long.");
        }

        if (cleanedCode.Length > AccessCodeMaxLength)
        {
            throw new InvalidOperationException($"Guest access code must be {AccessCodeMaxLength} characters or less.");
        }

        return cleanedCode;
    }

    [GeneratedRegex("^[a-z0-9._-]+$")]
    private static partial Regex UsernameRegex();
}
