using DocumentOperator.Application.Common.Interfaces;
using DocumentOperator.Application.Features.Documents.ExtractSwissQrCode;
using DocumentOperator.Domain.Models.ValueObjects;
using DocumentOperator.Domain.ValueObjects;
using FluentAssertions;
using Moq;
using Xunit;

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

public sealed class ExtractSwissQrCodeHandlerTests
{
    private readonly Mock<ISwissQrCodeProcessor> _mockQrCodeProcessor;
    private readonly ExtractSwissQrCodeHandler _handler;

    public ExtractSwissQrCodeHandlerTests()
    {
        _mockQrCodeProcessor = new Mock<ISwissQrCodeProcessor>();
        _handler = new ExtractSwissQrCodeHandler(_mockQrCodeProcessor.Object);
    }

    [Fact]
    public async Task Handle_ValidRequest_ReturnsQrCodeDataAndReferences()
    {
        // Arrange
        var references = new List<string> { "REF-001", "REF-002" };
        var pdfBase64 = "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovQ29udGVudHMgNCAwIFIKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0xlbmd0aCAzMgo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKEhlbGxvKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjEgMDAwMDAgbiAKMDAwMDAwMDIxMyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDUKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjI5NAolJUVPRgo=";
        var base64String = Base64String.Create(pdfBase64);
        var query = new ExtractSwissQrCodeQuery(references, base64String);

        var expectedQrCodeData = new SwissQrCodeData
        {
            QrType = "SPC",
            Version = "0200",
            CodingType = "1",
            Iban = "CH4431999123000889012",
            Creditor = new AddressData
            {
                AddressType = "S",
                Name = "Robert Schneider AG",
                Street = "Rue du Lac",
                BuildingNumber = "1268",
                PostalCode = "2501",
                City = "Biel",
                Country = "CH"
            },
            UltimateCreditor = null,
            Amount = 1949.75m,
            Currency = "CHF",
            UltimateDebtor = null,
            ReferenceType = "QRR",
            Reference = "210000000003139471430009017",
            UnstructuredMessage = "Order from 15.01.2025",
            BillInformation = null,
            AlternativeProcedureParameters = null
        };

        _mockQrCodeProcessor
            .Setup(x => x.ExtractSwissQrCodeAsync(It.IsAny<byte[]>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(expectedQrCodeData);

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

        // Assert
        result.Should().NotBeNull();
        result.References.Should().BeEquivalentTo(references);
        result.QrCodeData.Should().BeEquivalentTo(expectedQrCodeData);

        _mockQrCodeProcessor.Verify(
            x => x.ExtractSwissQrCodeAsync(It.IsAny<byte[]>(), It.IsAny<CancellationToken>()),
            Times.Once);
    }

    [Fact]
    public async Task Handle_QrCodeProcessorThrowsException_PropagatesException()
    {
        // Arrange
        var references = new List<string> { "REF-001" };
        var pdfBase64 = "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovQ29udGVudHMgNCAwIFIKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0xlbmd0aCAzMgo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKEhlbGxvKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjEgMDAwMDAgbiAKMDAwMDAwMDIxMyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDUKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjI5NAolJUVPRgo=";
        var base64String = Base64String.Create(pdfBase64);
        var query = new ExtractSwissQrCodeQuery(references, base64String);

        _mockQrCodeProcessor
            .Setup(x => x.ExtractSwissQrCodeAsync(It.IsAny<byte[]>(), It.IsAny<CancellationToken>()))
            .ThrowsAsync(new InvalidOperationException("QR Code processing failed"));

        // Act
        Func<Task> act = async () => await _handler.Handle(query, CancellationToken.None);

        // Assert
        await act.Should().ThrowAsync<InvalidOperationException>()
            .WithMessage("QR Code processing failed");
    }
}
