package de.assecutor.votianlt.service;

import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import de.assecutor.votianlt.model.InvoiceData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

@Service
@Slf4j
public class InvoicePdfGenerator {

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMANY);
    private static final int ITEMS_PER_PAGE = 15; // Maximum items per page before page break

    public byte[] generateInvoicePdf(InvoiceData invoiceData) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try (PdfWriter writer = new PdfWriter(baos);
             PdfDocument pdfDoc = new PdfDocument(writer);
             Document document = new Document(pdfDoc, PageSize.A4)) {

            // Set document margins
            document.setMargins(50, 50, 80, 50); // top, right, bottom, left

            PdfFont font = PdfFontFactory.createFont("Helvetica");
            PdfFont boldFont = PdfFontFactory.createFont("Helvetica-Bold");

            document.setFont(font);

            // Calculate totals
            calculateTotals(invoiceData);

            // Add header with company and customer info
            addHeader(document, invoiceData, boldFont, font);

            // Add invoice details
            addInvoiceDetails(document, invoiceData, boldFont, font);

            // Add invoice items (with page breaks if necessary)
            addInvoiceItems(document, invoiceData, boldFont, font);

            // Add totals
            addTotals(document, invoiceData, boldFont, font);

            // Add footer on all pages
            addFooter(pdfDoc, invoiceData, font);

            document.close();
        }

        log.info("Generated invoice PDF for invoice number: {}", invoiceData.getInvoiceNumber());
        return baos.toByteArray();
    }

    private void calculateTotals(InvoiceData invoiceData) {
        BigDecimal subtotal = BigDecimal.ZERO;
        BigDecimal vatAmount = BigDecimal.ZERO;

        for (InvoiceData.InvoiceItem item : invoiceData.getItems()) {
            BigDecimal itemTotal = item.getQuantity().multiply(item.getUnitPrice());
            item.setTotalPrice(itemTotal);
            subtotal = subtotal.add(itemTotal);

            // Calculate VAT for this item
            BigDecimal itemVat = itemTotal.multiply(item.getVatRate())
                    .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            vatAmount = vatAmount.add(itemVat);
        }

        invoiceData.setSubtotal(subtotal);
        invoiceData.setVatAmount(vatAmount);
        invoiceData.setTotalAmount(subtotal.add(vatAmount));
    }

    private void addHeader(Document document, InvoiceData invoiceData, PdfFont boldFont, PdfFont font) {
        // Create header table with company info (left) and customer info (right)
        Table headerTable = new Table(UnitValue.createPercentArray(new float[]{50, 50}))
                .setWidth(UnitValue.createPercentValue(100))
                .setMarginBottom(20);

        // Company information (left side)
        Cell companyCell = new Cell()
                .setBorder(Border.NO_BORDER)
                .setVerticalAlignment(com.itextpdf.layout.properties.VerticalAlignment.TOP);

        companyCell.add(new Paragraph(invoiceData.getCompanyName())
                .setFont(boldFont).setFontSize(14));
        companyCell.add(new Paragraph(invoiceData.getCompanyStreet() + " " +
                invoiceData.getCompanyHouseNumber()).setFont(font).setFontSize(10));
        companyCell.add(new Paragraph(invoiceData.getCompanyZip() + " " +
                invoiceData.getCompanyCity()).setFont(font).setFontSize(10));

        if (invoiceData.getCompanyPhone() != null) {
            companyCell.add(new Paragraph("Tel: " + invoiceData.getCompanyPhone())
                    .setFont(font).setFontSize(10));
        }
        if (invoiceData.getCompanyEmail() != null) {
            companyCell.add(new Paragraph("E-Mail: " + invoiceData.getCompanyEmail())
                    .setFont(font).setFontSize(10));
        }

        // Customer information (right side)
        Cell customerCell = new Cell()
                .setBorder(Border.NO_BORDER)
                .setVerticalAlignment(com.itextpdf.layout.properties.VerticalAlignment.TOP);

        customerCell.add(new Paragraph("Rechnungsempfänger:")
                .setFont(boldFont).setFontSize(10));
        customerCell.add(new Paragraph(invoiceData.getCustomerName())
                .setFont(boldFont).setFontSize(12));
        customerCell.add(new Paragraph(invoiceData.getCustomerStreet() + " " +
                invoiceData.getCustomerHouseNumber()).setFont(font).setFontSize(10));
        customerCell.add(new Paragraph(invoiceData.getCustomerZip() + " " +
                invoiceData.getCustomerCity()).setFont(font).setFontSize(10));

        if (invoiceData.getCustomerCountry() != null &&
            !invoiceData.getCustomerCountry().equalsIgnoreCase("Deutschland")) {
            customerCell.add(new Paragraph(invoiceData.getCustomerCountry())
                    .setFont(font).setFontSize(10));
        }

        headerTable.addCell(companyCell);
        headerTable.addCell(customerCell);
        document.add(headerTable);
    }

    private void addInvoiceDetails(Document document, InvoiceData invoiceData, PdfFont boldFont, PdfFont font) {
        // Invoice title
        document.add(new Paragraph("RECHNUNG")
                .setFont(boldFont)
                .setFontSize(20)
                .setTextAlignment(TextAlignment.CENTER)
                .setMarginTop(20)
                .setMarginBottom(20));

        // Invoice details table
        Table detailsTable = new Table(UnitValue.createPercentArray(new float[]{30, 20, 30, 20}))
                .setWidth(UnitValue.createPercentValue(100))
                .setMarginBottom(20);

        detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph("Rechnungsnummer:").setFont(boldFont).setFontSize(10)));
        detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph(invoiceData.getInvoiceNumber()).setFont(font).setFontSize(10)));

        detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph("Rechnungsdatum:").setFont(boldFont).setFontSize(10)));
        detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph(invoiceData.getInvoiceDate().format(DATE_FORMATTER)).setFont(font).setFontSize(10)));

        if (invoiceData.getDueDate() != null) {
            detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                    .add(new Paragraph("Fälligkeitsdatum:").setFont(boldFont).setFontSize(10)));
            detailsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                    .add(new Paragraph(invoiceData.getDueDate().format(DATE_FORMATTER)).setFont(font).setFontSize(10)));
        }

        document.add(detailsTable);
    }

    private void addInvoiceItems(Document document, InvoiceData invoiceData, PdfFont boldFont, PdfFont font) {
        // Items table header
        Table itemsTable = new Table(UnitValue.createPercentArray(new float[]{40, 10, 10, 15, 10, 15}))
                .setWidth(UnitValue.createPercentValue(100))
                .setMarginBottom(10);

        // Header row
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("Beschreibung").setFont(boldFont).setFontSize(10)));
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("Menge").setFont(boldFont).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("Einheit").setFont(boldFont).setFontSize(10))
                .setTextAlignment(TextAlignment.CENTER));
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("Einzelpreis").setFont(boldFont).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("MwSt%").setFont(boldFont).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));
        itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                .add(new Paragraph("Gesamtpreis").setFont(boldFont).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));

        // Add items
        int itemCount = 0;
        for (InvoiceData.InvoiceItem item : invoiceData.getItems()) {
            if (itemCount > 0 && itemCount % ITEMS_PER_PAGE == 0) {
                // Add current table and start new page
                document.add(itemsTable);
                document.add(new com.itextpdf.layout.element.AreaBreak());

                // Create new table with header
                itemsTable = new Table(UnitValue.createPercentArray(new float[]{40, 10, 10, 15, 10, 15}))
                        .setWidth(UnitValue.createPercentValue(100))
                        .setMarginBottom(10);

                // Re-add header
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("Beschreibung").setFont(boldFont).setFontSize(10)));
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("Menge").setFont(boldFont).setFontSize(10))
                        .setTextAlignment(TextAlignment.RIGHT));
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("Einheit").setFont(boldFont).setFontSize(10))
                        .setTextAlignment(TextAlignment.CENTER));
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("Einzelpreis").setFont(boldFont).setFontSize(10))
                        .setTextAlignment(TextAlignment.RIGHT));
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("MwSt%").setFont(boldFont).setFontSize(10))
                        .setTextAlignment(TextAlignment.RIGHT));
                itemsTable.addHeaderCell(new Cell().setBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .add(new Paragraph("Gesamtpreis").setFont(boldFont).setFontSize(10))
                        .setTextAlignment(TextAlignment.RIGHT));
            }

            itemsTable.addCell(new Cell().add(new Paragraph(item.getDescription()).setFont(font).setFontSize(9)));
            itemsTable.addCell(new Cell().add(new Paragraph(formatDecimal(item.getQuantity())).setFont(font).setFontSize(9))
                    .setTextAlignment(TextAlignment.RIGHT));
            itemsTable.addCell(new Cell().add(new Paragraph(item.getUnit() != null ? item.getUnit() : "").setFont(font).setFontSize(9))
                    .setTextAlignment(TextAlignment.CENTER));
            itemsTable.addCell(new Cell().add(new Paragraph(formatCurrency(item.getUnitPrice())).setFont(font).setFontSize(9))
                    .setTextAlignment(TextAlignment.RIGHT));
            itemsTable.addCell(new Cell().add(new Paragraph(formatDecimal(item.getVatRate()) + "%").setFont(font).setFontSize(9))
                    .setTextAlignment(TextAlignment.RIGHT));
            itemsTable.addCell(new Cell().add(new Paragraph(formatCurrency(item.getTotalPrice())).setFont(font).setFontSize(9))
                    .setTextAlignment(TextAlignment.RIGHT));

            itemCount++;
        }

        document.add(itemsTable);
    }

    private void addTotals(Document document, InvoiceData invoiceData, PdfFont boldFont, PdfFont font) {
        // Totals table (right-aligned)
        Table totalsTable = new Table(UnitValue.createPercentArray(new float[]{70, 30}))
                .setWidth(UnitValue.createPercentValue(100))
                .setMarginTop(20);

        // Empty cell for spacing
        totalsTable.addCell(new Cell().setBorder(Border.NO_BORDER));

        // Totals cell
        Cell totalsCell = new Cell().setBorder(Border.NO_BORDER);

        Table innerTotalsTable = new Table(UnitValue.createPercentArray(new float[]{70, 30}))
                .setWidth(UnitValue.createPercentValue(100));

        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph("Nettobetrag:").setFont(font).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));
        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph(formatCurrency(invoiceData.getSubtotal())).setFont(font).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));

        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph("MwSt (" + formatDecimal(invoiceData.getVatRate()) + "%):").setFont(font).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));
        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph(formatCurrency(invoiceData.getVatAmount())).setFont(font).setFontSize(10))
                .setTextAlignment(TextAlignment.RIGHT));

        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph("Rechnungsbetrag:").setFont(boldFont).setFontSize(12))
                .setTextAlignment(TextAlignment.RIGHT));
        innerTotalsTable.addCell(new Cell().setBorder(Border.NO_BORDER)
                .add(new Paragraph(formatCurrency(invoiceData.getTotalAmount())).setFont(boldFont).setFontSize(12))
                .setTextAlignment(TextAlignment.RIGHT));

        totalsCell.add(innerTotalsTable);
        totalsTable.addCell(totalsCell);

        document.add(totalsTable);
    }

    private void addFooter(PdfDocument pdfDoc, InvoiceData invoiceData, PdfFont font) {
        int numberOfPages = pdfDoc.getNumberOfPages();

        for (int i = 1; i <= numberOfPages; i++) {
            com.itextpdf.kernel.pdf.PdfPage page = pdfDoc.getPage(i);

            Document footerDoc = new Document(pdfDoc, PageSize.A4);
            footerDoc.setFont(font);

            // Footer content
            Table footerTable = new Table(UnitValue.createPercentArray(new float[]{33, 33, 34}))
                    .setWidth(UnitValue.createPercentValue(100))
                    .setFixedPosition(50, 20, 495); // x, y, width

            // Bank details
            Cell bankCell = new Cell().setBorder(Border.NO_BORDER);
            bankCell.add(new Paragraph("Bankverbindung:").setFont(font).setFontSize(8).setBold());
            bankCell.add(new Paragraph(invoiceData.getBankName()).setFont(font).setFontSize(7));
            bankCell.add(new Paragraph("IBAN: " + invoiceData.getIban()).setFont(font).setFontSize(7));
            bankCell.add(new Paragraph("BIC: " + invoiceData.getBic()).setFont(font).setFontSize(7));

            // Tax information
            Cell taxCell = new Cell().setBorder(Border.NO_BORDER);
            taxCell.add(new Paragraph("Steuerliche Angaben:").setFont(font).setFontSize(8).setBold());
            if (invoiceData.getTaxNumber() != null) {
                taxCell.add(new Paragraph("Steuernr.: " + invoiceData.getTaxNumber()).setFont(font).setFontSize(7));
            }
            if (invoiceData.getVatId() != null) {
                taxCell.add(new Paragraph("USt-IdNr.: " + invoiceData.getVatId()).setFont(font).setFontSize(7));
            }

            // Company details
            Cell companyCell = new Cell().setBorder(Border.NO_BORDER);
            if (invoiceData.getCommercialRegister() != null) {
                companyCell.add(new Paragraph(invoiceData.getCommercialRegister()).setFont(font).setFontSize(7));
            }
            if (invoiceData.getManagingDirector() != null) {
                companyCell.add(new Paragraph("Geschäftsführer: " + invoiceData.getManagingDirector()).setFont(font).setFontSize(7));
            }

            footerTable.addCell(bankCell);
            footerTable.addCell(taxCell);
            footerTable.addCell(companyCell);

            footerDoc.add(footerTable);
            footerDoc.close();
        }
    }

    private String formatCurrency(BigDecimal amount) {
        return String.format(Locale.GERMANY, "%.2f €", amount);
    }

    private String formatDecimal(BigDecimal amount) {
        return String.format(Locale.GERMANY, "%.2f", amount);
    }
}