using DocumentOperator.Application.Common.Interfaces;
using DocumentOperator.Domain.Models.ValueObjects;
using FluentValidation;
using MediatR;

namespace DocumentOperator.Application.AddAnnotation;

/// <summary>
/// Command to add an annotation to a PDF document.
/// </summary>
public record AddAnnotationCommand : IRequest<byte[]>
{
    public required Stream PdfStream { get; init; }
    public required AnnotationType AnnotationType { get; init; }
    public required int PageNumber { get; init; }
    public required (double X1, double Y1, double X2, double Y2) Rectangle { get; init; }
    public string? Content { get; init; }
    public string? Author { get; init; }
    public string? Color { get; init; }
    public TextMarkupStyle? TextMarkupStyle { get; init; }
    public AnnotationOrigin Origin { get; init; } = AnnotationOrigin.BottomLeft;
}

/// <summary>
/// Handler for AddAnnotationCommand.
/// </summary>
public class AddAnnotationHandler(IPdfProcessor pdfProcessor) : IRequestHandler<AddAnnotationCommand, byte[]>
{
    public async Task<byte[]> Handle(AddAnnotationCommand request, CancellationToken cancellationToken)
    {
        return await pdfProcessor.AddAnnotationAsync(
            request.PdfStream,
            request.AnnotationType,
            request.PageNumber,
            request.Rectangle,
            request.Content,
            request.Author,
            request.Color,
            request.TextMarkupStyle,
            request.Origin);
    }
}

/// <summary>
/// Validator for AddAnnotationCommand.
/// </summary>
public class AddAnnotationValidator : AbstractValidator<AddAnnotationCommand>
{
    public AddAnnotationValidator()
    {
        RuleFor(x => x.PdfStream)
            .NotNull()
            .WithMessage("PDF stream is required");

        RuleFor(x => x.PageNumber)
            .GreaterThan(0)
            .WithMessage("Page number must be greater than 0");

        RuleFor(x => x.Content)
            .NotEmpty()
            .When(x => x.AnnotationType == AnnotationType.FreeText || x.AnnotationType == AnnotationType.StickyNote)
            .WithMessage("Content is required for FreeText and StickyNote annotations");

        RuleFor(x => x.TextMarkupStyle)
            .NotNull()
            .When(x => x.AnnotationType == AnnotationType.TextMarkup)
            .WithMessage("TextMarkupStyle is required for TextMarkup annotations");

        RuleFor(x => x.Color)
            .Matches("^[0-9A-Fa-f]{6}$")
            .When(x => !string.IsNullOrWhiteSpace(x.Color))
            .WithMessage("Color must be a 6-digit hex value (e.g., 'FF0000' for red)");

        RuleFor(x => x.Rectangle)
            .Must(r => r.X2 > r.X1 && r.Y2 > r.Y1)
            .WithMessage("Rectangle coordinates must define a valid area (X2 > X1 and Y2 > Y1)");
    }
}
