using DocumentOperator.Application.SwissQrCode.Queries;
using FluentValidation;

namespace DocumentOperator.Application.SwissQrCode.Queries;

/// <summary>
/// Validates ExtractSwissQrCodeQuery before handler execution.
/// Ensures exactly ONE input method is provided (either PdfBytes OR Base64Pdf, not both, not none).
/// </summary>
public sealed class ExtractSwissQrCodeQueryValidator : AbstractValidator<ExtractSwissQrCodeQuery>
{
    public ExtractSwissQrCodeQueryValidator()
    {
        RuleFor(x => x)
            .Must(HasExactlyOneInput)
            .WithMessage("Either PdfBytes or Base64Pdf must be provided, but not both");

        // Validate Base64 format if provided
        When(x => !string.IsNullOrWhiteSpace(x.Base64Pdf), () =>
        {
            RuleFor(x => x.Base64Pdf)
                .Must(BeValidBase64)
                .WithMessage("Invalid Base64 format");
        });

        // Validate byte array if provided
        When(x => x.PdfBytes != null, () =>
        {
            RuleFor(x => x.PdfBytes)
                .NotEmpty()
                .WithMessage("PdfBytes cannot be empty");
        });
    }

    private static bool HasExactlyOneInput(ExtractSwissQrCodeQuery request)
    {
        var hasPdfBytes = request.PdfBytes != null && request.PdfBytes.Length > 0;
        var hasBase64 = !string.IsNullOrWhiteSpace(request.Base64Pdf);

        // XOR: exactly one must be true
        return hasPdfBytes ^ hasBase64;
    }

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

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