using Books.Api.Invoicing.Pdf;
using AwesomeAssertions;
using QuestPDF.Infrastructure;

namespace Books.Api.Tests.Invoicing;

/// <summary>
/// Unit tests for the InvoicePdfGenerator.
/// </summary>
[Trait("Category", "Unit")]
public class InvoicePdfGeneratorTests
{
    private readonly InvoicePdfGenerator _generator;

    public InvoicePdfGeneratorTests()
    {
        // Ensure QuestPDF license is set for tests
        QuestPDF.Settings.License = LicenseType.Community;
        _generator = new InvoicePdfGenerator();
    }

    [Fact]
    public void Generate_WithValidData_ProducesPdfBytes()
    {
        // Arrange
        var data = CreateSampleInvoiceData();

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
        pdfBytes.Should().StartWith([0x25, 0x50, 0x44, 0x46]); // PDF magic bytes "%PDF"
    }

    [Fact]
    public void Generate_WithMultipleLines_ProducesPdf()
    {
        // Arrange
        var data = CreateSampleInvoiceData(lineCount: 10);

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
        pdfBytes.Length.Should().BeGreaterThan(1000); // PDF should be substantial
    }

    [Fact]
    public void Generate_WithSingleLine_ProducesPdf()
    {
        // Arrange
        var data = CreateSampleInvoiceData(lineCount: 1);

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithDiscount_ProducesPdf()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Lines =
            [
                new InvoicePdfLineItem
                {
                    LineNumber = 1,
                    Description = "Produkt med rabat",
                    Quantity = 10,
                    Unit = "stk",
                    UnitPrice = 100m,
                    DiscountPercent = 15m,
                    VatCode = "U25",
                    AmountExVat = 850m,
                    AmountVat = 212.50m,
                    AmountTotal = 1062.50m
                }
            ],
            AmountExVat = 850m,
            AmountVat = 212.50m,
            AmountTotal = 1062.50m,
            VatSummary =
            [
                new VatSummaryLine
                {
                    VatCode = "U25",
                    VatRate = 0.25m,
                    BasisAmount = 850m,
                    VatAmount = 212.50m
                }
            ]
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithMultipleVatCodes_ShowsVatSummary()
    {
        // Arrange
        var data = CreateDataWithMixedVatCodes();

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithDanishCharacters_HandlesEncoding()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            CompanyName = "Møller & Sønner ApS",
            CustomerName = "Børge Åkeson",
            Notes = "Tak for ordren! Vi ses igen. Æbler, øl og åben dør."
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithLongDescription_HandlesWrapping()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Lines =
            [
                new InvoicePdfLineItem
                {
                    LineNumber = 1,
                    Description = "Dette er en meget lang beskrivelse af en ydelse der inkluderer mange detaljer om hvad der er leveret, hvornår det er leveret, og hvordan det er udført. Beskrivelsen fortsætter for at teste tekst-wrapping funktionaliteten i PDF generatoren.",
                    Quantity = 1,
                    Unit = "stk",
                    UnitPrice = 5000m,
                    DiscountPercent = 0,
                    VatCode = "U25",
                    AmountExVat = 5000m,
                    AmountVat = 1250m,
                    AmountTotal = 6250m
                }
            ],
            AmountExVat = 5000m,
            AmountVat = 1250m,
            AmountTotal = 6250m,
            VatSummary =
            [
                new VatSummaryLine { VatCode = "U25", VatRate = 0.25m, BasisAmount = 5000m, VatAmount = 1250m }
            ]
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithNotes_IncludesNotesSection()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Notes = "Betalingsfrist overholdes venligst. Ved forsinket betaling beregnes morarenter."
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithReference_IncludesReference()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Reference = "PO-2024-001234"
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithZeroVatLines_HandlesCorrectly()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Lines =
            [
                new InvoicePdfLineItem
                {
                    LineNumber = 1,
                    Description = "EU-ydelse (momsfri)",
                    Quantity = 1,
                    Unit = "stk",
                    UnitPrice = 10000m,
                    DiscountPercent = 0,
                    VatCode = "UEU",
                    AmountExVat = 10000m,
                    AmountVat = 0m,
                    AmountTotal = 10000m
                }
            ],
            AmountExVat = 10000m,
            AmountVat = 0m,
            AmountTotal = 10000m,
            VatSummary =
            [
                new VatSummaryLine { VatCode = "UEU", VatRate = 0m, BasisAmount = 10000m, VatAmount = 0m }
            ]
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithDecimalQuantity_FormatsCorrectly()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            Lines =
            [
                new InvoicePdfLineItem
                {
                    LineNumber = 1,
                    Description = "Konsulentydelse",
                    Quantity = 7.5m,
                    Unit = "timer",
                    UnitPrice = 850m,
                    DiscountPercent = 0,
                    VatCode = "U25",
                    AmountExVat = 6375m,
                    AmountVat = 1593.75m,
                    AmountTotal = 7968.75m
                }
            ],
            AmountExVat = 6375m,
            AmountVat = 1593.75m,
            AmountTotal = 7968.75m,
            VatSummary =
            [
                new VatSummaryLine { VatCode = "U25", VatRate = 0.25m, BasisAmount = 6375m, VatAmount = 1593.75m }
            ]
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithBankDetails_IncludesPaymentInfo()
    {
        // Arrange
        var data = CreateSampleInvoiceData() with
        {
            CompanyBankName = "Nordea",
            CompanyBankRegNo = "2191",
            CompanyBankAccountNo = "0012345678",
            CompanyIban = "DK8920000012345678",
            CompanyBic = "NDEADKKK"
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
        pdfBytes.Should().StartWith([0x25, 0x50, 0x44, 0x46]); // PDF magic bytes
    }

    [Fact]
    public void Generate_WithPartialBankDetails_ProducesPdf()
    {
        // Arrange - Only Danish bank details, no IBAN/BIC
        var data = CreateSampleInvoiceData() with
        {
            CompanyBankName = "Jyske Bank",
            CompanyBankRegNo = "5064",
            CompanyBankAccountNo = "1234567",
            CompanyIban = null,
            CompanyBic = null
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    [Fact]
    public void Generate_WithNoBankDetails_ProducesPdf()
    {
        // Arrange - No bank details at all
        var data = CreateSampleInvoiceData() with
        {
            CompanyBankName = null,
            CompanyBankRegNo = null,
            CompanyBankAccountNo = null,
            CompanyIban = null,
            CompanyBic = null
        };

        // Act
        var pdfBytes = _generator.Generate(data);

        // Assert
        pdfBytes.Should().NotBeNullOrEmpty();
    }

    #region Test Data Helpers

    private static InvoicePdfData CreateSampleInvoiceData(int lineCount = 3)
    {
        var lines = Enumerable.Range(1, lineCount)
            .Select(i => new InvoicePdfLineItem
            {
                LineNumber = i,
                Description = $"Konsulentydelse - uge {i}",
                Quantity = 40,
                Unit = "timer",
                UnitPrice = 850m,
                DiscountPercent = 0,
                VatCode = "U25",
                AmountExVat = 34000m,
                AmountVat = 8500m,
                AmountTotal = 42500m
            })
            .ToList();

        var totalExVat = lines.Sum(l => l.AmountExVat);
        var totalVat = lines.Sum(l => l.AmountVat);
        var total = lines.Sum(l => l.AmountTotal);

        return new InvoicePdfData
        {
            CompanyName = "Test Firma ApS",
            CompanyCvr = "12345678",
            CompanyAddress = "Testvej 123",
            CompanyPostalCode = "2100",
            CompanyCity = "København Ø",
            CompanyCountry = "DK",

            // Bank details
            CompanyBankName = "Danske Bank",
            CompanyBankRegNo = "3409",
            CompanyBankAccountNo = "1234567890",
            CompanyIban = "DK5000400440116243",
            CompanyBic = "DABADKKK",

            CustomerName = "Kunde ApS",
            CustomerCvr = "87654321",
            CustomerAddress = "Kundevej 456",
            CustomerPostalCode = "8000",
            CustomerCity = "Aarhus C",
            CustomerCountry = "DK",
            CustomerNumber = "K-001",

            InvoiceNumber = "2024-0001",
            InvoiceDate = new DateOnly(2024, 1, 15),
            DueDate = new DateOnly(2024, 2, 14),
            PaymentTermsDays = 30,
            Currency = "DKK",

            Lines = lines,
            AmountExVat = totalExVat,
            AmountVat = totalVat,
            AmountTotal = total,
            VatSummary =
            [
                new VatSummaryLine
                {
                    VatCode = "U25",
                    VatRate = 0.25m,
                    BasisAmount = totalExVat,
                    VatAmount = totalVat
                }
            ]
        };
    }

    private static InvoicePdfData CreateDataWithMixedVatCodes()
    {
        var lines = new List<InvoicePdfLineItem>
        {
            new()
            {
                LineNumber = 1,
                Description = "Dansk ydelse (25% moms)",
                Quantity = 1,
                Unit = "stk",
                UnitPrice = 10000m,
                DiscountPercent = 0,
                VatCode = "U25",
                AmountExVat = 10000m,
                AmountVat = 2500m,
                AmountTotal = 12500m
            },
            new()
            {
                LineNumber = 2,
                Description = "EU-ydelse (0% moms)",
                Quantity = 1,
                Unit = "stk",
                UnitPrice = 5000m,
                DiscountPercent = 0,
                VatCode = "UEU",
                AmountExVat = 5000m,
                AmountVat = 0m,
                AmountTotal = 5000m
            }
        };

        return new InvoicePdfData
        {
            CompanyName = "Mixed VAT Company ApS",
            CompanyCvr = "11111111",
            CompanyAddress = "Momsvej 1",
            CompanyPostalCode = "1000",
            CompanyCity = "København K",
            CompanyCountry = "DK",

            CustomerName = "EU Customer GmbH",
            CustomerCvr = "DE123456789",
            CustomerAddress = "Hauptstraße 1",
            CustomerPostalCode = "10115",
            CustomerCity = "Berlin",
            CustomerCountry = "DE",
            CustomerNumber = "K-EU-001",

            InvoiceNumber = "2024-0002",
            InvoiceDate = new DateOnly(2024, 2, 1),
            DueDate = new DateOnly(2024, 3, 1),
            PaymentTermsDays = 30,
            Currency = "DKK",

            Lines = lines,
            AmountExVat = 15000m,
            AmountVat = 2500m,
            AmountTotal = 17500m,
            VatSummary =
            [
                new VatSummaryLine { VatCode = "U25", VatRate = 0.25m, BasisAmount = 10000m, VatAmount = 2500m },
                new VatSummaryLine { VatCode = "UEU", VatRate = 0m, BasisAmount = 5000m, VatAmount = 0m }
            ]
        };
    }

    #endregion
}
