using AutoMapper;
using DocumentOperator.Application.Common.DTOs;
using DocumentOperator.Application.Common.Interfaces;
using DocumentOperator.Application.ValidatePdf.Queries;
using DocumentOperator.Domain.Common.Exceptions;
using FluentAssertions;
using Moq;
using Xunit;

namespace DocumentOperator.Tests.Unit.Application.Features.ValidatePdf;

public class ValidatePdfHandlerTests
{
    private readonly Mock<IPdfProcessor> _mockPdfProcessor;
    private readonly Mock<IMapper> _mockMapper;
    private readonly ValidatePdfQueryHandler _handler;

    public ValidatePdfHandlerTests()
    {
        _mockPdfProcessor = new Mock<IPdfProcessor>();
        _mockMapper = new Mock<IMapper>();
        _handler = new ValidatePdfQueryHandler(_mockPdfProcessor.Object, _mockMapper.Object);
    }

    [Fact]
    public async Task Handle_ValidPdf_ReturnsPdfMetadata()
    {
        // Arrange
        var pdfBytes = "%PDF"u8.ToArray(); // "%PDF"
        var query = new ValidatePdfQuery { PdfStream = new MemoryStream(pdfBytes) };

        var domainMetadata = new PdfMetadata(
            pageCount: 5,
            fileSizeBytes: 1024,
            pdfVersion: "1.4",
            hasAttachments: false,
            attachmentCount: 0
        );

        var expectedDto = new PdfValidationResult(
            PageCount: 5,
            FileSizeBytes: 1024,
            FileSizeMB: 0.00,
            PdfVersion: "1.4",
            HasAttachments: false,
            AttachmentCount: 0
        );

        _mockPdfProcessor
            .Setup(x => x.ValidateAsync(It.IsAny<Stream>()))
            .ReturnsAsync(domainMetadata);

        _mockMapper
            .Setup(x => x.Map<PdfValidationResult>(domainMetadata))
            .Returns(expectedDto);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.Should().NotBeNull();
        result.PageCount.Should().Be(5);
        result.FileSizeBytes.Should().Be(1024);
        result.PdfVersion.Should().Be("1.4");
        result.HasAttachments.Should().BeFalse();
        result.AttachmentCount.Should().Be(0);

        _mockPdfProcessor.Verify(x => x.ValidateAsync(It.IsAny<Stream>()), Times.Once);
        _mockMapper.Verify(x => x.Map<PdfValidationResult>(domainMetadata), Times.Once);
    }

    [Fact]
    public async Task Handle_PdfProcessorThrowsException_PropagatesException()
    {
        // Arrange
        var pdfBytes = "%PDF"u8.ToArray(); // "%PDF"
        var query = new ValidatePdfQuery { PdfStream = new MemoryStream(pdfBytes) };

        _mockPdfProcessor
            .Setup(x => x.ValidateAsync(It.IsAny<Stream>()))
            .ThrowsAsync(new BadRequestException("Invalid PDF format"));

        // Act & Assert
        var exception = await Assert.ThrowsAsync<BadRequestException>(
            () => _handler.Handle(query, CancellationToken.None)
        );

        exception.Message.Should().Be("Invalid PDF format");
        _mockPdfProcessor.Verify(x => x.ValidateAsync(It.IsAny<Stream>()), Times.Once);
    }
}
