using FluentValidation;
using ChatService.API.Application.Commands.Keys;

namespace ChatService.API.Application.Validations.Keys;

/// <summary>
/// EN: Validator for RegisterUserKeysCommand.
/// VI: Validator cho RegisterUserKeysCommand.
/// </summary>
public class RegisterUserKeysCommandValidator : AbstractValidator<RegisterUserKeysCommand>
{
    public RegisterUserKeysCommandValidator()
    {
        RuleFor(x => x.IdentityUserId)
            .NotEmpty()
            .WithMessage("Identity user ID is required");

        RuleFor(x => x.DisplayName)
            .NotEmpty()
            .MaximumLength(255)
            .WithMessage("Display name must not exceed 255 characters");

        RuleFor(x => x.IdentityPublicKey)
            .NotEmpty()
            .Must(BeValidBase64)
            .WithMessage("Identity public key must be valid Base64");

        RuleFor(x => x.SignedPreKey)
            .NotEmpty()
            .Must(BeValidBase64)
            .WithMessage("Signed pre-key must be valid Base64");

        RuleFor(x => x.SignedPreKeySignature)
            .NotEmpty()
            .Must(BeValidBase64)
            .WithMessage("Signed pre-key signature must be valid Base64");

        RuleForEach(x => x.OneTimePreKeys)
            .ChildRules(preKey =>
            {
                preKey.RuleFor(k => k.KeyId)
                    .GreaterThanOrEqualTo(0)
                    .WithMessage("Key ID must be non-negative");

                preKey.RuleFor(k => k.PublicKey)
                    .NotEmpty()
                    .Must(BeValidBase64)
                    .WithMessage("Public key must be valid Base64");
            });
    }

    private static bool BeValidBase64(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return false;

        try
        {
            Convert.FromBase64String(value);
            return true;
        }
        catch
        {
            return false;
        }
    }
}

/// <summary>
/// EN: Validator for RotatePreKeyCommand.
/// VI: Validator cho RotatePreKeyCommand.
/// </summary>
public class RotatePreKeyCommandValidator : AbstractValidator<RotatePreKeyCommand>
{
    public RotatePreKeyCommandValidator()
    {
        RuleFor(x => x.ChatUserId)
            .NotEmpty()
            .WithMessage("Chat user ID is required");

        RuleFor(x => x.NewSignedPreKey)
            .NotEmpty()
            .Must(BeValidBase64)
            .WithMessage("New signed pre-key must be valid Base64");

        RuleFor(x => x.NewSignedPreKeySignature)
            .NotEmpty()
            .Must(BeValidBase64)
            .WithMessage("New signed pre-key signature must be valid Base64");
    }

    private static bool BeValidBase64(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return false;

        try
        {
            Convert.FromBase64String(value);
            return true;
        }
        catch
        {
            return false;
        }
    }
}

/// <summary>
/// EN: Validator for UploadOneTimeKeysCommand.
/// VI: Validator cho UploadOneTimeKeysCommand.
/// </summary>
public class UploadOneTimeKeysCommandValidator : AbstractValidator<UploadOneTimeKeysCommand>
{
    public UploadOneTimeKeysCommandValidator()
    {
        RuleFor(x => x.ChatUserId)
            .NotEmpty()
            .WithMessage("Chat user ID is required");

        RuleFor(x => x.OneTimePreKeys)
            .NotEmpty()
            .WithMessage("At least one pre-key is required");

        RuleFor(x => x.OneTimePreKeys.Count())
            .LessThanOrEqualTo(100)
            .WithMessage("Cannot upload more than 100 pre-keys at once");

        RuleForEach(x => x.OneTimePreKeys)
            .ChildRules(preKey =>
            {
                preKey.RuleFor(k => k.KeyId)
                    .GreaterThanOrEqualTo(0)
                    .WithMessage("Key ID must be non-negative");

                preKey.RuleFor(k => k.PublicKey)
                    .NotEmpty()
                    .Must(BeValidBase64)
                    .WithMessage("Public key must be valid Base64");
            });
    }

    private static bool BeValidBase64(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return false;

        try
        {
            Convert.FromBase64String(value);
            return true;
        }
        catch
        {
            return false;
        }
    }
}
