import {PDFDocument, StandardFonts, rgb} from "pdf-lib"
import dayjs from "dayjs"
import {renderAsCurrency, splitStringBySpace} from "./stringRendering";
import {FastifyInstance} from "fastify";
import { GetObjectCommand } from "@aws-sdk/client-s3";
import { s3 } from "./s3";
import { secrets } from "./secrets";
import bwipjs from "bwip-js"

const getCoordinatesForPDFLib = (x:number ,y:number, page:any) => {
    /*
    * @param x the wanted X Parameter in Millimeters from Top Left
    * @param y the wanted Y Parameter in Millimeters from Top Left
    * @param page the page Object
    *
    * @returns x,y object
    * */


    let retX = x * 2.83
    let retY = page.getHeight()-(y*2.83)

    return {
        x: retX,
        y: retY
    }
}

const getRightAlignedX = (rightEdgeMm: number, text: string, size: number, font: any, page: any) => {
    return getCoordinatesForPDFLib(rightEdgeMm, 0, page).x - font.widthOfTextAtSize(text, size)
}

const normalizePaymentQrText = (value: any, maxLength: number) => {
    return String(value || "")
        .replace(/\r?\n/g, " ")
        .replace(/[^\x20-\x7EÄÖÜäöüß]/g, "")
        .trim()
        .slice(0, maxLength)
}

const normalizeIban = (value: any) => String(value || "").replace(/\s+/g, "").toUpperCase()

const getPaymentQrAmount = (value: any) => {
    if (typeof value === "number" && Number.isFinite(value)) return value

    const normalized = String(value || "")
        .replace(/[^\d,.-]/g, "")
        .replace(/\./g, "")
        .replace(",", ".")

    const amount = Number(normalized)

    return Number.isFinite(amount) ? amount : 0
}

const getPaymentQrCodeBuffer = async (invoiceData: any) => {
    if (invoiceData?.payment_type && invoiceData.payment_type !== "transfer") return null

    const paymentQr = invoiceData?.paymentQr || {}
    const iban = normalizeIban(paymentQr.iban)
    const recipientName = normalizePaymentQrText(paymentQr.recipientName || paymentQr.name, 70)
    const amount = getPaymentQrAmount(paymentQr.amount ?? invoiceData?.total?.totalSumToPay)

    if (!iban || !recipientName || amount <= 0) return null

    const epcPayload = [
        "BCD",
        "002",
        "1",
        "SCT",
        normalizePaymentQrText(paymentQr.bic, 11),
        recipientName,
        iban,
        `EUR${amount.toFixed(2)}`,
        "",
        normalizePaymentQrText(paymentQr.remittance || invoiceData?.documentNumber || invoiceData?.title, 140),
        "",
    ].join("\n")

    return bwipjs.toBuffer({
        bcid: "qrcode",
        text: epcPayload,
        scale: 4,
        includetext: false,
    })
}


const getBackgroundSourceBuffer = async (server:FastifyInstance, path:string) => {

    console.log(path)

    const { Body } = await s3.send(
        new GetObjectCommand({
            Bucket: secrets.S3_BUCKET,
            Key: path
        })
    )

    const chunks: Buffer[] = []
    for await (const chunk of Body as any) {
        chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))
    }

    return Buffer.concat(chunks)
}

const getDuration = (time) => {
    const minutes = Math.floor(dayjs(time.stopped_at).diff(dayjs(time.started_at),'minutes',true))
    const hours = Math.floor(minutes/60)
    return {
        //dezimal: dez,
        hours: hours,
        minutes: minutes,
        composed: `${hours}:${String(minutes % 60).padStart(2,"0")} Std`
    }
}


export const createInvoicePDF = async (server:FastifyInstance, returnMode, invoiceData, backgroundPath:string) => {
    const deliveryNoteLikeDocumentTypes = ["deliveryNotes", "packingSlips"]
    const isPackingSlip = invoiceData?.type === "packingSlips"

    const genPDF = async (invoiceData, backgroundSourceBuffer) => {
        const pdfDoc = await PDFDocument.create()

        const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
        const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold)
        const paymentQrCodeBuffer = await getPaymentQrCodeBuffer(invoiceData)
        const paymentQrCode = paymentQrCodeBuffer ? await pdfDoc.embedPng(paymentQrCodeBuffer) : null

        let pages = []
        let pageCounter = 1


        //const backgroundPdfSourceBuffer = await fetch("/Briefpapier.pdf").then((res) => res.arrayBuffer())
        const backgroudPdf = await PDFDocument.load(backgroundSourceBuffer)

        const firstPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[0])
        const secondPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[backgroudPdf.getPages().length > 1 ? 1 : 0])

        //
        const page1 = pdfDoc.addPage()

        //

        page1.drawPage(firstPageBackground, {
            x: 0,
            y: 0,
        })
        //
        pages.push(page1)
        //


        //Falzmarke 1
        pages[pageCounter - 1].drawLine({
            start: getCoordinatesForPDFLib(0, 105, page1),
            end: getCoordinatesForPDFLib(5, 105, page1),
            thickness: 0.2,
            color: rgb(0, 0, 0),
            opacity: 1
        })

        //Lochmarke
        pages[pageCounter - 1].drawLine({
            start: getCoordinatesForPDFLib(0, 148.5, page1),
            end: getCoordinatesForPDFLib(5, 148.5, page1),
            thickness: 0.2,
            color: rgb(0, 0, 0),
            opacity: 1
        })

        //Falzmarke 2
        pages[pageCounter - 1].drawLine({
            start: getCoordinatesForPDFLib(0, 210, page1),
            end: getCoordinatesForPDFLib(5, 210, page1),
            thickness: 0.2,
            color: rgb(0, 0, 0),
            opacity: 1
        })


        /*page1.drawLine({
            start: getCoordinatesForPDFLib(20,45,page1),
            end: getCoordinatesForPDFLib(105,45,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/

        if (!invoiceData.addressLine) console.log("Missing Addressline")

        pages[pageCounter - 1].drawText(invoiceData.adressLine, {
            ...getCoordinatesForPDFLib(21, 48, page1),
            size: 6,
            color: rgb(0, 0, 0),
            lineHeight: 6,
            opacity: 1,
            maxWidth: 240
        })


        /*page1.drawLine({
            start: getCoordinatesForPDFLib(20,50,page1),
            end: getCoordinatesForPDFLib(105,50,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/

        let partLinesAdded = 0
        invoiceData.recipient.forEach((info, index) => {


            let maxSplitLength = 35
            let splittedContent = splitStringBySpace(info, maxSplitLength)


            splittedContent.forEach((part, partIndex) => {
                if (partIndex === 0) {
                    pages[pageCounter - 1].drawText(part, {
                        ...getCoordinatesForPDFLib(21, 55 + index * 5 + partLinesAdded * 5, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240
                    })
                } else {
                    partLinesAdded++

                    pages[pageCounter - 1].drawText(part, {
                        ...getCoordinatesForPDFLib(21, 55 + index * 5 + partLinesAdded * 5, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240
                    })
                }

                /*if(partIndex > 0) partLinesAdded++

                pages[pageCounter - 1].drawText(part, {
                    y: getCoordinatesForPDFLib(21,55+index*5+partLinesAdded*5, page1).y,
                    x: getCoordinatesForPDFLib(21,55+index*5+partLinesAdded*5,page1).x + 230 - font.widthOfTextAtSize(part,10),
                    size:10,
                    color:rgb(0,0,0),
                    lineHeight:10,
                    opacity: 1,
                    maxWidth: 240
                })*/

            })
        })

        //Rechts

        partLinesAdded = 0

        invoiceData.info.forEach((info, index) => {

            let maxSplitLength = 34
            let splittedContent = splitStringBySpace(info.content, maxSplitLength)


            splittedContent.forEach((part, partIndex) => {
                if (partIndex === 0) {
                    pages[pageCounter - 1].drawText(info.label, {
                        ...getCoordinatesForPDFLib(116, 55 + index * 5 + partLinesAdded * 5, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240
                    })
                }

                if (partIndex > 0) partLinesAdded++

                pages[pageCounter - 1].drawText(part, {
                    y: getCoordinatesForPDFLib(116, 55 + index * 5 + partLinesAdded * 5, page1).y,
                    x: getCoordinatesForPDFLib(116, 55 + index * 5 + partLinesAdded * 5, page1).x + 230 - font.widthOfTextAtSize(part, 10),
                    size: 10,
                    color: rgb(0, 0, 0),
                    lineHeight: 10,
                    opacity: 1,
                    maxWidth: 240
                })

            })
        })


        /*page1.drawLine({
            start: getCoordinatesForPDFLib(125,90,page1),
            end: getCoordinatesForPDFLib(200,90,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/

        //Title

        /*page1.drawLine({
            start: getCoordinatesForPDFLib(20,95,page1),
            end: getCoordinatesForPDFLib(200,95,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/

        if (!invoiceData.title) console.log("Missing Title")

        pages[pageCounter - 1].drawText(invoiceData.title, {
            ...getCoordinatesForPDFLib(20, 100, page1),
            size: 13,
            color: rgb(0, 0, 0),
            lineHeight: 15,
            opacity: 1,
            maxWidth: 500
        })

        /*page1.drawLine({
            start: getCoordinatesForPDFLib(20,105,page1),
            end: getCoordinatesForPDFLib(200,105,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/
        if (!invoiceData.description) console.log("Missing Description")

        if (invoiceData.description) {
            pages[pageCounter - 1].drawText(invoiceData.description, {
                ...getCoordinatesForPDFLib(20, 112, page1),
                size: 13,
                color: rgb(0, 0, 0),
                lineHeight: 15,
                opacity: 1,
                maxWidth: 500
            })
        }

        if (!invoiceData.startText) console.log("Missing StartText")


        pages[pageCounter - 1].drawText(invoiceData.startText, {
            ...getCoordinatesForPDFLib(20, 119, page1),
            size: 10,
            color: rgb(0, 0, 0),
            lineHeight: 10,
            opacity: 1,
            maxWidth: 500
        })

        /*page1.drawLine({
            start: getCoordinatesForPDFLib(20,115,page1),
            end: getCoordinatesForPDFLib(200,115,page1),
            thickness: 0.5,
            color: rgb(0,0,0),
            opacity: 1
        })*/

        pages[pageCounter - 1].drawLine({
            start: getCoordinatesForPDFLib(20, 140, page1),
            end: getCoordinatesForPDFLib(199, 140, page1),
            thickness: 0.1,
            color: rgb(0, 0, 0),
            opacity: 1,
        })

        /*pages[pageCounter - 1].drawRectangle({
            ...getCoordinatesForPDFLib(20,140, page1),
            width: 180 * 2.83,
            height: 8 * 2.83,
            color: rgb(0,0,0),
            opacity: 0,
            borderWidth: 0.1
        })*/

        //Header

        pages[pageCounter - 1].drawText("Pos", {
            ...getCoordinatesForPDFLib(21, 137, page1),
            size: 12,
            color: rgb(0, 0, 0),
            lineHeight: 12,
            opacity: 1,
            maxWidth: 240,
            font: fontBold
        })

        pages[pageCounter - 1].drawText("Menge", {
            ...getCoordinatesForPDFLib(35, 137, page1),
            size: 12,
            color: rgb(0, 0, 0),
            lineHeight: 12,
            opacity: 1,
            maxWidth: 240,
            font: fontBold
        })

        pages[pageCounter - 1].drawText("Bezeichnung", {
            ...getCoordinatesForPDFLib(52, 137, page1),
            size: 12,
            color: rgb(0, 0, 0),
            lineHeight: 12,
            opacity: 1,
            maxWidth: 240,
            font: fontBold
        })

        if (isPackingSlip) {
            pages[pageCounter - 1].drawText("Check", {
                ...getCoordinatesForPDFLib(180, 137, page1),
                size: 12,
                color: rgb(0, 0, 0),
                lineHeight: 12,
                opacity: 1,
                maxWidth: 240,
                font: fontBold
            })
        }

        if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
            pages[pageCounter - 1].drawText("Steuer", {
                ...getCoordinatesForPDFLib(135, 137, page1),
                size: 12,
                color: rgb(0, 0, 0),
                lineHeight: 12,
                opacity: 1,
                maxWidth: 240,
                font: fontBold
            })

            const unitPriceHeader = "Einheitspreis"
            pages[pageCounter - 1].drawText(unitPriceHeader, {
                y: getCoordinatesForPDFLib(150, 137, page1).y,
                x: getRightAlignedX(177, unitPriceHeader, 12, fontBold, page1),
                size: 12,
                color: rgb(0, 0, 0),
                lineHeight: 12,
                opacity: 1,
                maxWidth: 240,
                font: fontBold
            })

            pages[pageCounter - 1].drawText("Gesamt", {
                y: getCoordinatesForPDFLib(25, 137, page1).y,
                x: getCoordinatesForPDFLib(25, 137, page1).x + 490 - fontBold.widthOfTextAtSize("Gesamt", 12),
                size: 12,
                color: rgb(0, 0, 0),
                lineHeight: 12,
                opacity: 1,
                maxWidth: 240,
                font: fontBold
            })
        }


        let rowHeight = 145.5

        let pageIndex = 0

        const getTitleKey = (row) => `${row.pos} - ${row.text}`
        const getTransferSumText = (row) => {
            const transferSum = invoiceData.total.titleSumsTransfer[getTitleKey(row)]

            return transferSum ? `Übertrag: ${transferSum}` : null
        }

        invoiceData.rows.forEach((row, index) => {

            if (!["pagebreak", "title", "text"].includes(row.mode)) {


                if (!row.pos) console.log("Missing Row Pos")

                pages[pageCounter - 1].drawText(String(row.pos), {
                    ...getCoordinatesForPDFLib(21, rowHeight, page1),
                    size: 10,
                    color: rgb(0, 0, 0),
                    lineHeight: 10,
                    opacity: 1,
                    maxWidth: 240
                })

                if (!row.quantity) console.log("Missing Row Quantity")
                if (!row.unit) console.log("Missing Row Unit")

                pages[pageCounter - 1].drawText((row.optional || row.alternative) ? `(${row.quantity} ${row.unit})` : `${row.quantity} ${row.unit}`, {
                    ...getCoordinatesForPDFLib(35, rowHeight, page1),
                    size: 10,
                    color: rgb(0, 0, 0),
                    lineHeight: 10,
                    opacity: 1,
                    maxWidth: 240
                })

                if (isPackingSlip) {
                    pages[pageCounter - 1].drawRectangle({
                        ...getCoordinatesForPDFLib(182, rowHeight + 1, page1),
                        width: 12,
                        height: 12,
                        borderColor: rgb(0, 0, 0),
                        borderWidth: 0.8,
                        opacity: 1,
                        borderOpacity: 1,
                    })
                }

                let rowTextLines = 0

                if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
                    pages[pageCounter - 1].drawText(splitStringBySpace(row.text, 35).join("\n"), {
                        ...getCoordinatesForPDFLib(52, rowHeight, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        font: fontBold
                    })
                    rowTextLines = splitStringBySpace(row.text, 35).length

                } else {
                    pages[pageCounter - 1].drawText(splitStringBySpace(row.text, isPackingSlip ? 68 : 80).join("\n"), {
                        ...getCoordinatesForPDFLib(52, rowHeight, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        font: fontBold
                    })

                    rowTextLines = splitStringBySpace(row.text, isPackingSlip ? 68 : 80).length
                }

                let rowDescriptionLines = 0

                if (row.descriptionText) {
                    if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
                        rowDescriptionLines = splitStringBySpace(row.descriptionText, 60).length
                        pages[pageCounter - 1].drawText(splitStringBySpace(row.descriptionText, 60).join("\n"), {
                            ...getCoordinatesForPDFLib(52, rowHeight + (rowTextLines * 5), page1),
                            size: 10,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                        })

                    } else {
                        rowDescriptionLines = splitStringBySpace(row.descriptionText, isPackingSlip ? 68 : 80).length
                        pages[pageCounter - 1].drawText(splitStringBySpace(row.descriptionText, isPackingSlip ? 68 : 80).join("\n"), {
                            ...getCoordinatesForPDFLib(52, rowHeight + (rowTextLines * 5), page1),
                            size: 10,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                        })
                    }
                }


                if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
                    pages[pageCounter - 1].drawText(`${row.taxPercent} %`, {
                        ...getCoordinatesForPDFLib(135, rowHeight, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240
                    })
                    pages[pageCounter - 1].drawText(row.price, {
                        y: getCoordinatesForPDFLib(150, rowHeight, page1).y,
                        x: getRightAlignedX(177, row.price, 10, font, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240
                    })


                    pages[pageCounter - 1].drawText((row.optional || row.alternative) ? `(${row.rowAmount})` : row.rowAmount, {
                        y: getCoordinatesForPDFLib(25, rowHeight, page1).y,
                        x: getCoordinatesForPDFLib(25, rowHeight, page1).x + 490 - font.widthOfTextAtSize((row.optional || row.alternative) ? `(${row.rowAmount})` : row.rowAmount, 10),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 240,
                    })

                    if (row.discountPercent > 0) {

                        let text = row.discountText

                        if (row.optional) text = `Optional - ${text}`
                        if (row.alternative) text = `Alternativ - ${text}`


                        pages[pageCounter - 1].drawText(text, {
                            y: getCoordinatesForPDFLib(25, rowHeight + 5, page1).y,
                            x: getCoordinatesForPDFLib(25, rowHeight + 5, page1).x + 490 - font.widthOfTextAtSize(text, 8),
                            size: 8,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                            maxWidth: 240,
                        })
                    } else if (row.optional) {
                        pages[pageCounter - 1].drawText("Optional", {
                            y: getCoordinatesForPDFLib(25, rowHeight + 5, page1).y,
                            x: getCoordinatesForPDFLib(25, rowHeight + 5, page1).x + 490 - font.widthOfTextAtSize("Optional", 8),
                            size: 8,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                            maxWidth: 240,
                        })
                    } else if (row.alternative) {
                        pages[pageCounter - 1].drawText("Alternativ", {
                            y: getCoordinatesForPDFLib(25, rowHeight + 5, page1).y,
                            x: getCoordinatesForPDFLib(25, rowHeight + 5, page1).x + 490 - font.widthOfTextAtSize("Alternativ", 8),
                            size: 8,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                            maxWidth: 240,
                        })
                    }
                }

                if (row.descriptionText) {
                    rowHeight += rowDescriptionLines * 4.5 + rowTextLines * 5.5
                } else if (row.discountPercent) {
                    rowHeight += (rowTextLines + 1) * 5.5
                } else if (row.optional || row.alternative) {
                    rowHeight += (rowTextLines + 1) * 5.5
                } else {
                    rowHeight += rowTextLines * 5.5
                }


                pageIndex += 1


            } else if (row.mode === 'pagebreak') {

                console.log(invoiceData.rows[index + 1])

                if (invoiceData.rows[index + 1]?.mode === 'title') {
                    const transferSumText = getTransferSumText(invoiceData.rows[index + 1])
                    if (transferSumText) {
                        pages[pageCounter - 1].drawText(transferSumText, {
                            y: getCoordinatesForPDFLib(21, rowHeight - 2, page1).y,
                            x: getCoordinatesForPDFLib(21, rowHeight - 2, page1).x + 500 - fontBold.widthOfTextAtSize(transferSumText, 10),
                            size: 10,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                            maxWidth: 240,
                            font: fontBold
                        })
                    }
                }


                const page = pdfDoc.addPage()

                page.drawPage(secondPageBackground, {
                    x: 0,
                    y: 0,
                })

                //Falzmarke 1
                page.drawLine({
                    start: getCoordinatesForPDFLib(0, 105, page1),
                    end: getCoordinatesForPDFLib(7, 105, page1),
                    thickness: 0.25,
                    color: rgb(0, 0, 0),
                    opacity: 1
                })

                //Lochmarke
                page.drawLine({
                    start: getCoordinatesForPDFLib(0, 148.5, page1),
                    end: getCoordinatesForPDFLib(7, 148.5, page1),
                    thickness: 0.25,
                    color: rgb(0, 0, 0),
                    opacity: 1
                })

                //Falzmarke 2
                page.drawLine({
                    start: getCoordinatesForPDFLib(0, 210, page1),
                    end: getCoordinatesForPDFLib(7, 210, page1),
                    thickness: 0.25,
                    color: rgb(0, 0, 0),
                    opacity: 1
                })

                page.drawText("Pos", {
                    ...getCoordinatesForPDFLib(21, 22, page1),
                    size: 12,
                    color: rgb(0, 0, 0),
                    lineHeight: 12,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })

                page.drawText("Menge", {
                    ...getCoordinatesForPDFLib(35, 22, page1),
                    size: 12,
                    color: rgb(0, 0, 0),
                    lineHeight: 12,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })

                page.drawText("Bezeichnung", {
                    ...getCoordinatesForPDFLib(52, 22, page1),
                    size: 12,
                    color: rgb(0, 0, 0),
                    lineHeight: 12,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })

                if (isPackingSlip) {
                    page.drawText("Check", {
                        ...getCoordinatesForPDFLib(180, 22, page1),
                        size: 12,
                        color: rgb(0, 0, 0),
                        lineHeight: 12,
                        opacity: 1,
                        maxWidth: 240,
                        font: fontBold
                    })
                }

                if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
                    page.drawText("Steuer", {
                        ...getCoordinatesForPDFLib(135, 22, page1),
                        size: 12,
                        color: rgb(0, 0, 0),
                        lineHeight: 12,
                        opacity: 1,
                        maxWidth: 240,
                        font: fontBold
                    })

                    const unitPriceHeader = "Einheitspreis"
                    page.drawText(unitPriceHeader, {
                        y: getCoordinatesForPDFLib(150, 22, page1).y,
                        x: getRightAlignedX(177, unitPriceHeader, 12, fontBold, page1),
                        size: 12,
                        color: rgb(0, 0, 0),
                        lineHeight: 12,
                        opacity: 1,
                        maxWidth: 240,
                        font: fontBold
                    })

                    page.drawText("Gesamt", {
                        y: getCoordinatesForPDFLib(25, 22, page1).y,
                        x: getCoordinatesForPDFLib(25, 22, page1).x + 490 - fontBold.widthOfTextAtSize("Gesamt", 12),
                        size: 12,
                        color: rgb(0, 0, 0),
                        lineHeight: 12,
                        opacity: 1,
                        maxWidth: 240,
                        font: fontBold
                    })
                }

                pageCounter += 1;
                pageIndex = 0;
                rowHeight = 30;

                pages.push(page)

            } else if (row.mode === 'title') {
                if (index === 0 || pageIndex === 0) {
                    rowHeight += 3
                } else {
                    const transferSumText = getTransferSumText(row)
                    if (transferSumText) {
                        pages[pageCounter - 1].drawText(transferSumText, {
                            y: getCoordinatesForPDFLib(21, rowHeight - 2, page1).y,
                            x: getCoordinatesForPDFLib(21, rowHeight - 2, page1).x + 500 - fontBold.widthOfTextAtSize(transferSumText, 10),
                            size: 10,
                            color: rgb(0, 0, 0),
                            lineHeight: 10,
                            opacity: 1,
                            maxWidth: 240,
                            font: fontBold
                        })
                    }

                    pages[pageCounter - 1].drawLine({
                        start: getCoordinatesForPDFLib(20, rowHeight, page1),
                        end: getCoordinatesForPDFLib(199, rowHeight, page1),
                        thickness: 0.2,
                        color: rgb(0, 0, 0),
                        opacity: 1,
                    })
                    rowHeight += 5
                }

                const titleLevel = Math.min(Math.max(Number(row.titleLevel) || 1, 1), 3)
                const titleTextSize = titleLevel === 1 ? 12 : titleLevel === 2 ? 11 : 10
                const titleTextX = 35 + ((titleLevel - 1) * 7)

                pages[pageCounter - 1].drawText(String(row.pos), {
                    ...getCoordinatesForPDFLib(21, rowHeight, page1),
                    size: 10,
                    color: rgb(0, 0, 0),
                    lineHeight: 10,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })

                pages[pageCounter - 1].drawText(splitStringBySpace(row.text, 60).join("\n"), {
                    ...getCoordinatesForPDFLib(titleTextX, rowHeight, page1),
                    size: titleTextSize,
                    color: rgb(0, 0, 0),
                    lineHeight: titleTextSize,
                    opacity: 1,
                    maxWidth: 500,
                    font: fontBold
                })

                rowHeight += splitStringBySpace(row.text, 60).length * (titleLevel === 1 ? 4.5 : 4)
            } else if (row.mode === 'text') {
                if (index === 0 || pageIndex === 0) {
                    rowHeight += 3
                }

                if (row.descriptionText) {
                    pages[pageCounter - 1].drawText(splitStringBySpace(row.descriptionText, 70).join("\n"), {
                        ...getCoordinatesForPDFLib(35, rowHeight, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                    })

                    rowHeight += (splitStringBySpace(row.descriptionText, 70) || []).length * 4
                    rowHeight += 4
                }
            }
            console.log(rowHeight)
        })


        let endTextDiff = 35

        if (!deliveryNoteLikeDocumentTypes.includes(invoiceData.type)) {
            pages[pageCounter - 1].drawLine({
                start: getCoordinatesForPDFLib(20, rowHeight, page1),
                end: getCoordinatesForPDFLib(198, rowHeight, page1),
                thickness: 0.2,
                color: rgb(0, 0, 0),
                opacity: 1,
            })
            rowHeight += 6


            if (Object.keys(invoiceData.total.titleSums).length > 0) {
                Object.keys(invoiceData.total.titleSums).forEach((key, index) => {
                    pages[pageCounter - 1].drawText(splitStringBySpace(key, 60).join("\n"), {
                        ...getCoordinatesForPDFLib(21, rowHeight, page1),
                        size: 11,
                        color: rgb(0, 0, 0),
                        lineHeight: 11,
                        opacity: 1,
                        font: fontBold
                    })

                    pages[pageCounter - 1].drawText(invoiceData.total.titleSums[key], {
                        y: getCoordinatesForPDFLib(21, rowHeight, page1).y,
                        x: getCoordinatesForPDFLib(21, rowHeight, page1).x + 500 - fontBold.widthOfTextAtSize(invoiceData.total.titleSums[key], 11),
                        size: 11,
                        color: rgb(0, 0, 0),
                        lineHeight: 11,
                        opacity: 1,
                        maxWidth: 240,
                        font: fontBold
                    })

                    rowHeight += splitStringBySpace(key, 60).length * 5
                })

                /*let titleSumsArray = Object.keys(invoiceData.total.titleSums)
                titleSumsArray.forEach(sum => {
                    let length = splitStringBySpace(sum,60).length
                    rowHeight += length *6
                })*/

                //rowHeight += Object.keys(invoiceData.total.titleSums)

                pages[pageCounter - 1].drawLine({
                    start: getCoordinatesForPDFLib(20, rowHeight, page1),
                    end: getCoordinatesForPDFLib(198, rowHeight, page1),
                    thickness: 0.2,
                    color: rgb(0, 0, 0),
                    opacity: 1,
                })

                rowHeight += 5
            }

            invoiceData.totalArray.forEach((item, index) => {
                pages[pageCounter - 1].drawText(item.label, {
                    ...getCoordinatesForPDFLib(21, rowHeight + 8 * index, page1),
                    size: 11,
                    color: rgb(0, 0, 0),
                    lineHeight: 11,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })

                pages[pageCounter - 1].drawText(item.content, {
                    y: getCoordinatesForPDFLib(21, rowHeight + 8 * index, page1).y,
                    x: getCoordinatesForPDFLib(21, rowHeight + 8 * index, page1).x + 500 - fontBold.widthOfTextAtSize(item.content, 11),
                    size: 11,
                    color: rgb(0, 0, 0),
                    lineHeight: 11,
                    opacity: 1,
                    maxWidth: 240,
                    font: fontBold
                })
            })

            if (invoiceData.taxType !== "13b UStG" && invoiceData.taxType !== "19 UStG" && invoiceData.taxType !== "12.3 UStG") {

            } else {
                if (invoiceData.taxType === "13b UStG") {
                    pages[pageCounter - 1].drawText("Die Umsatzsteuer für diese Leistung schuldet nach §13b UStG der Leistungsempfänger", {
                        ...getCoordinatesForPDFLib(21, rowHeight + invoiceData.totalArray.length * 8, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 500
                    })
                } else if (invoiceData.taxType === "19 UStG") {
                    pages[pageCounter - 1].drawText("Als Kleinunternehmer im Sinne von § 19 Abs. 1 UStG wird keine Umsatzsteuer berechnet.", {
                        ...getCoordinatesForPDFLib(21, rowHeight + invoiceData.totalArray.length * 8, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 500
                    })
                } else if (invoiceData.taxType === "12.3 UStG") {
                    pages[pageCounter - 1].drawText("Umsatzsteuer befreite Lieferung/Leistung für PV-Anlagen gemäß § 12 Absatz 3 UStG.", {
                        ...getCoordinatesForPDFLib(21, rowHeight + invoiceData.totalArray.length * 8, page1),
                        size: 10,
                        color: rgb(0, 0, 0),
                        lineHeight: 10,
                        opacity: 1,
                        maxWidth: 500
                    })
                }


            }


            pages[pageCounter - 1].drawText(invoiceData.endText, {
                ...getCoordinatesForPDFLib(21, rowHeight + endTextDiff + (invoiceData.totalArray.length - 3) * 8, page1),
                size: 10,
                color: rgb(0, 0, 0),
                lineHeight: 10,
                opacity: 1,
                maxWidth: 500
            })
        }

        if (paymentQrCode) {
            const lastPage = pages[pages.length - 1]
            const mm = 2.83
            const qrSize = 32 * mm
            const rightMargin = 20 * mm
            const bottomMargin = 40 * mm
            const labelGap = 5 * mm
            const qrX = lastPage.getWidth() - rightMargin - qrSize
            const qrY = bottomMargin

            lastPage.drawText("Überweisung per QR-Code", {
                x: qrX,
                y: qrY + qrSize + labelGap,
                size: 8,
                color: rgb(0, 0, 0),
                lineHeight: 8,
                opacity: 1,
                maxWidth: qrSize,
                font: fontBold,
            })

            lastPage.drawImage(paymentQrCode, {
                x: qrX,
                y: qrY,
                width: qrSize,
                height: qrSize,
            })
        }

        return await pdfDoc.saveAsBase64()

    }

    const pdfBytes = await genPDF(invoiceData, await getBackgroundSourceBuffer(server,backgroundPath))

    if(returnMode === "base64"){
        return {
            mimeType: 'application/pdf',
            base64: pdfBytes
        }
    } else {
        return null
    }
}

export const createTimeSheetPDF = async (server: FastifyInstance, returnMode, data, backgroundPath: string) => {

    const genPDF = async (input, backgroundSourceBuffer) => {
        const pdfDoc = await PDFDocument.create()

        const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
        const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold)

        let pages = []
        let pageCounter = 1

        const backgroudPdf = await PDFDocument.load(backgroundSourceBuffer)

        const firstPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[0])
        // Fallback für einseitige Hintergründe
        const secondPageBackground = await pdfDoc.embedPage(backgroudPdf.getPages()[backgroudPdf.getPages().length > 1 ? 1 : 0])

        const page1 = pdfDoc.addPage()

        page1.drawPage(firstPageBackground, {
            x: 0,
            y: 0,
        })

        pages.push(page1)

        console.log("PDF Input Data:", input)

        // ---------------------------------------------------------
        // DATEN-EXTRAKTION MIT FALLBACKS (Calculated vs. Standard)
        // ---------------------------------------------------------

        // Summen: Bevorzuge calculated..., falls vorhanden
        const sumSubmitted = input.calculatedSumWorkingMinutesSubmitted ?? input.sumWorkingMinutesSubmitted ?? 0;
        const sumApproved = input.calculatedSumWorkingMinutesApproved ?? input.sumWorkingMinutesApproved ?? 0;

        // Saldi: Bevorzuge calculated...
        const saldoSubmitted = input.calculatedSaldoSubmitted ?? input.saldoSubmitted ?? input.saldoInOfficial ?? 0;
        const saldoApproved = input.calculatedSaldoApproved ?? input.saldoApproved ?? input.saldo ?? 0;

        // Andere Summen (diese sind meist korrekt vom Backend)
        const sumRecreation = input.sumWorkingMinutesRecreationDays ?? 0;
        const sumVacation = input.sumWorkingMinutesVacationDays ?? 0;
        const sumSick = input.sumWorkingMinutesSickDays ?? 0;
        const sumTarget = input.timeSpanWorkingMinutes ?? 0;

        // Hilfsfunktion zur Formatierung von Minuten -> HH:MM
        const fmtTime = (mins) => {
            const m = Math.floor(Math.abs(mins));
            return `${Math.floor(m / 60)}:${String(m % 60).padStart(2, "0")}`;
        };

        const fmtSaldo = (mins) => {
            const sign = Math.sign(mins) >= 0 ? "+" : "-";
            return `${sign} ${fmtTime(mins)}`;
        }


        // ---------------------------------------------------------
        // HEADER TEXTE ZEICHNEN
        // ---------------------------------------------------------

        pages[pageCounter - 1].drawText(`Anwesenheitsauswertung`,{
            x: getCoordinatesForPDFLib(20,60,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,60,pages[pageCounter -1]).y,
            size: 15,
            font: fontBold
        })

        pages[pageCounter - 1].drawText(`Mitarbeiter: ${input.full_name || ''}`,{
            x: getCoordinatesForPDFLib(20,70,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,70,pages[pageCounter -1]).y,
            size: 10,
        })
        pages[pageCounter - 1].drawText(`Nummer: ${input.employee_number || '-'}`,{
            x: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,75,pages[pageCounter -1]).y,
            size: 10,
        })

        // Zeile 1: Eingereicht & Genehmigt
        pages[pageCounter - 1].drawText(`Eingereicht: ${fmtTime(sumSubmitted)} Std`,{
            x: getCoordinatesForPDFLib(20,80,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,80,pages[pageCounter -1]).y,
            size: 10,
        })
        pages[pageCounter - 1].drawText(`Genehmigt: ${fmtTime(sumApproved)} Std`,{
            x: getCoordinatesForPDFLib(20,85,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,85,pages[pageCounter -1]).y,
            size: 10,
        })

        // Zeile 2: Ausgleichstage
        pages[pageCounter - 1].drawText(`Feiertagsausgleich: ${fmtTime(sumRecreation)} Std`,{
            x: getCoordinatesForPDFLib(20,90,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,90,pages[pageCounter -1]).y,
            size: 10,
        })
        pages[pageCounter - 1].drawText(`Urlaubsausgleich: ${fmtTime(sumVacation)} Std`,{
            x: getCoordinatesForPDFLib(20,95,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,95,pages[pageCounter -1]).y,
            size: 10,
        })
        pages[pageCounter - 1].drawText(`Krankheitsausgleich: ${fmtTime(sumSick)} Std`,{
            x: getCoordinatesForPDFLib(20,100,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,100,pages[pageCounter -1]).y,
            size: 10,
        })

        // Zeile 3: Soll & Saldo
        pages[pageCounter - 1].drawText(`Soll Stunden: ${fmtTime(sumTarget)} Std`,{
            x: getCoordinatesForPDFLib(20,105,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,105,pages[pageCounter -1]).y,
            size: 10,
        })

        // Wir nutzen hier die Begriffe "Inoffiziell" (Submitted Saldo) und "Saldo" (Approved Saldo)
        pages[pageCounter - 1].drawText(`Inoffizielles Saldo: ${fmtSaldo(saldoSubmitted)} Std`,{
            x: getCoordinatesForPDFLib(20,110,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,110,pages[pageCounter -1]).y,
            size: 10,
        })
        pages[pageCounter - 1].drawText(`Saldo: ${fmtSaldo(saldoApproved)} Std`,{
            x: getCoordinatesForPDFLib(20,115,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,115,pages[pageCounter -1]).y,
            size: 10,
        })

        // Tabellen-Header
        pages[pageCounter - 1].drawText(`Start:`,{
            x: getCoordinatesForPDFLib(20,125,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(20,125,pages[pageCounter -1]).y,
            size: 10,
        })

        pages[pageCounter - 1].drawText(`Ende:`,{
            x: getCoordinatesForPDFLib(60,125,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(60,125,pages[pageCounter -1]).y,
            size: 10,
        })

        pages[pageCounter - 1].drawText(`Dauer:`,{
            x: getCoordinatesForPDFLib(100,125,pages[pageCounter -1]).x,
            y: getCoordinatesForPDFLib(100,125,pages[pageCounter -1]).y,
            size: 10,
        })

        // ---------------------------------------------------------
        // TABELLE GENERIEREN (Spans verarbeiten)
        // ---------------------------------------------------------

        let rowHeight = 130

        // WICHTIG: input.spans verwenden, fallback auf input.times (altes Format)
        // Wir filtern leere Einträge raus
        const rawItems = (input.spans || input.times || []).filter(t => t);

        // Sortierung umkehren (neueste zuletzt für den Druck? Oder wie gewünscht)
        // Im Original war es .reverse().
        let reversedInput = rawItems.slice().reverse();

        let splitted = []
        const splittedLength = Math.floor((reversedInput.length - 25) / 40)

        // Erste Seite hat weniger Platz wegen Header (25 Zeilen)
        splitted.push(reversedInput.slice(0,25))

        let lastIndex = 25
        for (let i = 0; i < splittedLength; ++i ) {
            splitted.push(reversedInput.slice(lastIndex, lastIndex + (i + 1) * 40))
            lastIndex = lastIndex + (i + 1) * 40 + 1
        }

        if(reversedInput.slice(lastIndex, reversedInput.length).length > 0) {
            splitted.push(reversedInput.slice(lastIndex, reversedInput.length))
        }

        console.log("PDF Pages Chunks:", splitted.length)

        splitted.forEach((chunk,index) => {
            if(index > 0) {
                const page = pdfDoc.addPage()

                page.drawPage(secondPageBackground, {
                    x: 0,
                    y: 0,
                })

                pages.push(page)
                pageCounter++
                rowHeight = 20
            }

            chunk.forEach(span => {
                // Mapping für Felder: spans nutzen 'startedAt', times nutzten 'started_at'
                const startStr = span.startedAt || span.started_at;
                const endStr = span.endedAt || span.stopped_at; // endedAt oder stopped_at

                // Dauer berechnen (da Spans keine duration_minutes haben)
                let durationStr = "";
                if (startStr && endStr) {
                    const diffMins = dayjs(endStr).diff(dayjs(startStr), 'minute');
                    durationStr = fmtTime(diffMins);
                } else if (span.duration_minutes) {
                    durationStr = fmtTime(span.duration_minutes);
                } else if (span.duration) { // Falls schon formatiert übergeben
                    durationStr = span.duration;
                }

                pages[pageCounter - 1].drawText(`${dayjs(startStr).format("HH:mm DD.MM.YY")}`,{
                    x: getCoordinatesForPDFLib(20,rowHeight,pages[pageCounter -1]).x,
                    y: getCoordinatesForPDFLib(20,rowHeight,pages[pageCounter -1]).y,
                    size: 10,
                })

                pages[pageCounter - 1].drawText(`${endStr ? dayjs(endStr).format("HH:mm DD.MM.YY") : 'läuft...'}`,{
                    x: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).x,
                    y: getCoordinatesForPDFLib(60,rowHeight,pages[pageCounter -1]).y,
                    size: 10,
                })

                pages[pageCounter - 1].drawText(`${durationStr}`,{
                    x: getCoordinatesForPDFLib(100,rowHeight,pages[pageCounter -1]).x,
                    y: getCoordinatesForPDFLib(100,rowHeight,pages[pageCounter -1]).y,
                    size: 10,
                })

                // Optional: Status anzeigen?
                /*pages[pageCounter - 1].drawText(`${span.status || span.state || ''}`,{
                    x: getCoordinatesForPDFLib(130,rowHeight,pages[pageCounter -1]).x,
                    y: getCoordinatesForPDFLib(130,rowHeight,pages[pageCounter -1]).y,
                    size: 8,
                })*/

                rowHeight += 6
            })
        })

        return await pdfDoc.saveAsBase64()
    }

    try {
        const pdfBytes = await genPDF(data, await getBackgroundSourceBuffer(server,backgroundPath))

        if(returnMode === "base64"){
            return {
                mimeType: 'application/pdf',
                base64: pdfBytes
            }
        } else {
            return "test"
        }
    } catch(error) {
        console.log(error)
        throw error; // Fehler weiterwerfen, damit er oben ankommt
    }
}
