import dayjs from "dayjs";
import quarterOfYear from "dayjs/plugin/quarterOfYear";
import axios from "axios";
import { eq, inArray, and } from "drizzle-orm"; // Drizzle Operatoren

// DEINE IMPORTS
import * as schema from "../../db/schema"; // Importiere dein Drizzle Schema
import { saveFile } from "../utils/files";
import {FastifyInstance} from "fastify";
import {useNextNumberRangeNumber} from "../utils/functions";
import {createInvoicePDF} from "../utils/pdf"; // Achtung: Muss Node.js Buffer unterstützen!
import { documentTemplateHandlebars } from "../utils/handlebars";

dayjs.extend(quarterOfYear);


export const executeManualGeneration = async (server:FastifyInstance,executionDate,templateIds,tenantId,executedBy) => {
    try {
        console.log(executedBy)

        const executionDayjs = dayjs(executionDate);

        console.log(`Starte manuelle Generierung für Tenant ${tenantId} am ${executionDate}`);

        // 1. Tenant laden (Drizzle)
        // Wir nehmen an, dass 'tenants' im Schema definiert ist
        const [tenant] = await server.db
            .select()
            .from(schema.tenants)
            .where(eq(schema.tenants.id, tenantId))
            .limit(1);

        if (!tenant) throw new Error(`Tenant mit ID ${tenantId} nicht gefunden.`);

        // 2. Templates laden
        const templates = await server.db
            .select()
            .from(schema.createddocuments)
            .where(
                and(
                    eq(schema.createddocuments.tenant, tenantId),
                    eq(schema.createddocuments.type, "serialInvoices"),
                    inArray(schema.createddocuments.id, templateIds)
                )
            );

        if (templates.length === 0) {
            console.warn("Keine passenden Vorlagen gefunden.");
            return [];
        }

        // 3. Folder & FileType IDs holen (Hilfsfunktionen unten)
        const folderId = await getFolderId(server,tenantId);
        const fileTypeId = await getFileTypeId(server,tenantId);

        const results = [];

        const [executionRecord] = await server.db
            .insert(schema.serialExecutions)
            .values({
                tenant: tenantId,
                executionDate: executionDayjs.toDate(),
                status: "draft",
                createdBy: executedBy,
                summary: `${templateIds.length} Vorlagen verarbeitet`
            })
            .returning();

        console.log(executionRecord);

        // 4. Loop durch die Templates
        for (const template of templates) {
            try {
                const resultId = await processSingleTemplate(
                    server,
                    template,
                    tenant,
                    executionDayjs,
                    folderId,
                    fileTypeId,
                    executedBy,
                    executionRecord.id
                );
                results.push({ id: template.id, status: "success", newDocumentId: resultId });
            } catch (e: any) {
                console.error(`Fehler bei Template ${template.id}:`, e);
                results.push({ id: template.id, status: "error", error: e.message });
            }
        }

        return results;
    } catch (error) {
        console.log(error);
    }
}

export const finishManualGeneration = async (server: FastifyInstance, executionId: number) => {
    try {
        console.log(`Beende Ausführung ${executionId}...`);

        // 1. Execution und Tenant laden

        const [executionRecord] = await server.db
            .select()
            .from(schema.serialExecutions)// @ts-ignore
            .where(eq(schema.serialExecutions.id, executionId))
            .limit(1);

        if (!executionRecord) throw new Error("Execution nicht gefunden");

        console.log(executionRecord);

        const tenantId = executionRecord.tenant;

        console.log(tenantId)

        // Tenant laden (für Settings etc.)
        const [tenant] = await server.db
            .select()
            .from(schema.tenants)
            .where(eq(schema.tenants.id, tenantId))
            .limit(1);

        // 2. Status auf "processing" setzen (optional, damit UI feedback hat)

        /*await server.db
            .update(schema.serialExecutions)
            .set({ status: "processing" })// @ts-ignore
            .where(eq(schema.serialExecutions.id, executionId));*/

        // 3. Alle erstellten Dokumente dieser Execution laden
        const documents = await server.db
            .select()
            .from(schema.createddocuments)
            .where(eq(schema.createddocuments.serialexecution, executionId));

        console.log(`${documents.length} Dokumente werden finalisiert...`);

        // 4. IDs für File-System laden (nur einmalig nötig)
        const folderId = await getFolderId(server, tenantId);
        const fileTypeId = await getFileTypeId(server, tenantId);

        // Globale Daten laden, die für alle gleich sind (Optimierung)
        const [units, products, services] = await Promise.all([
            server.db.select().from(schema.units),
            server.db.select().from(schema.products).where(eq(schema.products.tenant, tenantId)),
            server.db.select().from(schema.services).where(eq(schema.services.tenant, tenantId)),
        ]);

        let successCount = 0;
        let errorCount = 0;

        // 5. Loop durch Dokumente
        for (const doc of documents) {
            try {

                const [letterhead] = await Promise.all([
                    /*fetchById(server, schema.contacts, doc.contact),
                    fetchById(server, schema.customers, doc.customer),
                    fetchById(server, schema.authProfiles, doc.contactPerson), // oder createdBy, je nach Logik
                    fetchById(server, schema.projects, doc.project),
                    fetchById(server, schema.contracts, doc.contract),*/
                    doc.letterhead ? fetchById(server, schema.letterheads, doc.letterhead) : null
                ]);

                const pdfData = await getCloseData(
                    server,
                    doc,
                    tenant,
                    units,
                    products,
                    services,
                );

                console.log(pdfData);

                // D. PDF Generieren
                const pdfBase64 = await createInvoicePDF(server,"base64",pdfData, letterhead?.path);

                console.log(pdfBase64);

                // E. Datei speichern
                // @ts-ignore
                const fileBuffer = Buffer.from(pdfBase64.base64, "base64");
                const filename = `${pdfData.documentNumber}.pdf`;

                await saveFile(
                    server,
                    tenantId,
                    null, // User ID (hier ggf. executionRecord.createdBy nutzen wenn verfügbar)
                    fileBuffer,
                    folderId,
                    fileTypeId,
                    {
                        createddocument: doc.id,
                        filename: filename,
                        filesize: fileBuffer.length // Falls saveFile das braucht
                    }
                );

                // F. Dokument in DB final updaten
                await server.db
                    .update(schema.createddocuments)
                    .set({
                        state: "Gebucht",
                        documentNumber: pdfData.documentNumber,
                        title: pdfData.title,
                        pdf_path: filename // Optional, falls du den Pfad direkt am Doc speicherst
                    })
                    .where(eq(schema.createddocuments.id, doc.id));

                successCount++;

            } catch (innerErr) {
                console.error(`Fehler beim Finalisieren von Doc ID ${doc.id}:`, innerErr);
                errorCount++;
                // Optional: Status des einzelnen Dokuments auf Error setzen
            }
        }

        // 6. Execution abschließen
        const finalStatus = errorCount > 0 ? "error" : "completed"; // Oder 'completed' auch wenn Teilerfolge


        await server.db
            .update(schema.serialExecutions)
            .set({
                status: finalStatus,
                summary: `Abgeschlossen: ${successCount} erfolgreich, ${errorCount} Fehler.`
            })// @ts-ignore
            .where(eq(schema.serialExecutions.id, executionId));

        return { success: true, processed: successCount, errors: errorCount };

    } catch (error) {
        console.error("Critical Error in finishManualGeneration:", error);
        // Execution auf Error setzen
        // @ts-ignore
        await server.db
            .update(schema.serialExecutions)
            .set({ status: "error", summary: "Kritischer Fehler beim Finalisieren." })
            //@ts-ignore
            .where(eq(schema.serialExecutions.id, executionId));
        throw error;
    }
}


/**
 * Verarbeitet eine einzelne Vorlage
 */
async function processSingleTemplate(server: FastifyInstance, template: any, tenant: any,executionDate: dayjs.Dayjs,folderId: string,fileTypeId: string,executedBy: string,executionId: string) {
    // A. Zugehörige Daten parallel laden
    const [contact, customer, profile, project, contract, units, products, services, letterhead] = await Promise.all([
        fetchById(server, schema.contacts, template.contact),
        fetchById(server, schema.customers, template.customer),
        fetchById(server, schema.authProfiles, template.contactPerson),
        fetchById(server, schema.projects, template.project),
        fetchById(server, schema.contracts, template.contract),
        server.db.select().from(schema.units),
        server.db.select().from(schema.products).where(eq(schema.products.tenant, tenant.id)),
        server.db.select().from(schema.services).where(eq(schema.services.tenant, tenant.id)),
        template.letterhead ? fetchById(server, schema.letterheads, template.letterhead) : null
    ]);

    // B. Datumsberechnung (Logik aus dem Original)
    const { firstDate, lastDate } = calculateDateRange(template.serialConfig, executionDate);

    // C. Rechnungsnummer & Save Data
    const savePayload = await getSaveData(
        template,
        tenant,
        firstDate,
        lastDate,
        executionDate.toISOString(),
        executedBy
    );

    const payloadWithRelation = {
        ...savePayload,
        serialexecution: executionId
    };

    // D. Dokument in DB anlegen (Drizzle Insert)
    const [createdDoc] = await server.db
        .insert(schema.createddocuments)
        .values(payloadWithRelation)
        .returning(); // Wichtig für Postgres: returning() gibt das erstellte Objekt zurück

    return createdDoc.id;
}

// --- Drizzle Helper ---

async function fetchById(server: FastifyInstance, table: any, id: number | null) {
    if (!id) return null;
    const [result] = await server.db.select().from(table).where(eq(table.id, id)).limit(1);
    return result || null;
}

async function getFolderId(server:FastifyInstance, tenantId: number) {
    const [folder] = await server.db
        .select({ id: schema.folders.id })
        .from(schema.folders)
        .where(
            and(
                eq(schema.folders.tenant, tenantId),
                eq(schema.folders.function, "invoices"), // oder 'invoices', check deine DB
                eq(schema.folders.year, dayjs().format("YYYY"))
            )
        )
        .limit(1);
    return folder?.id;
}

async function getFileTypeId(server: FastifyInstance,tenantId: number) {
    const [tag] = await server.db
        .select({ id: schema.filetags.id })
        .from(schema.filetags)
        .where(
            and(
                eq(schema.filetags.tenant, tenantId),
                eq(schema.filetags.createdDocumentType, "invoices")
            )
        )
        .limit(1);
    return tag?.id;
}



// --- Logik Helper (Unverändert zur Business Logik) ---

function calculateDateRange(config: any, executionDate: dayjs.Dayjs) {
    // Basis nehmen
    let baseDate = executionDate;

    let firstDate = baseDate;
    let lastDate = baseDate;

    if (config.intervall === "monatlich" && config.dateDirection === "Rückwirkend") {
        // 1. Monat abziehen
        // 2. Start/Ende des Monats berechnen
        // 3. WICHTIG: Zeit hart auf 12:00:00 setzen, damit Zeitzonen das Datum nicht kippen
        firstDate = baseDate.subtract(1, "month").startOf("month").hour(12).minute(0).second(0).millisecond(0);
        lastDate = baseDate.subtract(1, "month").endOf("month").hour(12).minute(0).second(0).millisecond(0);

    } else if (config.intervall === "vierteljährlich" && config.dateDirection === "Rückwirkend") {

        firstDate = baseDate.subtract(1, "quarter").startOf("quarter").hour(12).minute(0).second(0).millisecond(0);
        lastDate = baseDate.subtract(1, "quarter").endOf("quarter").hour(12).minute(0).second(0).millisecond(0);
    }

    // Das Ergebnis ist nun z.B.:
    // firstDate: '2025-12-01T12:00:00.000Z' (Eindeutig der 1. Dezember)
    // lastDate:  '2025-12-31T12:00:00.000Z' (Eindeutig der 31. Dezember)

    return {
        firstDate: firstDate.toISOString(),
        lastDate: lastDate.toISOString()
    };
}

async function getSaveData(item: any, tenant: any, firstDate: string, lastDate: string, executionDate: string, executedBy: string) {
    const cleanRows = item.rows.map((row: any) => ({
        ...row,
        descriptionText: row.description || null,
    }));

    //const documentNumber = await this.useNextInvoicesNumber(item.tenant);

    return {
        tenant: item.tenant,
        type: "invoices",
        state: "Entwurf",
        customer: item.customer,
        contact: item.contact,
        contract: item.contract,
        address: item.address,
        project: item.project,
        costcentre: item.costcentre,
        documentDate: executionDate,
        deliveryDate: firstDate,
        deliveryDateEnd: lastDate,
        paymentDays: item.paymentDays,
        payment_type: item.payment_type,
        deliveryDateType: item.deliveryDateType,
        info: {}, // Achtung: Postgres erwartet hier valides JSON Objekt
        createdBy: item.createdBy,
        created_by: item.created_by,
        title: `Rechnung-Nr. XXX`,
        description: item.description,
        startText: item.startText,
        endText: item.endText,
        rows: cleanRows, // JSON Array
        contactPerson: item.contactPerson,
        linkedDocument: item.linkedDocument,
        letterhead: item.letterhead,
        taxType: item.taxType,
    };
}

async function getCloseData(server:FastifyInstance,item: any, tenant: any, units, products,services) {
    const documentNumber = await useNextNumberRangeNumber(server,tenant.id,"invoices");

    console.log(item);

    const [contact, customer, project, contract, bankAccounts] = await Promise.all([
        fetchById(server, schema.contacts, item.contact),
        fetchById(server, schema.customers, item.customer),
        fetchById(server, schema.projects, item.project),
        fetchById(server, schema.contracts, item.contract),
        server.db
            .select()
            .from(schema.bankaccounts)
            .where(and(eq(schema.bankaccounts.tenant, tenant.id), eq(schema.bankaccounts.archived, false), eq(schema.bankaccounts.expired, false)))

    ]);

    const profile = (await server.db.select().from(schema.authProfiles).where(and(eq(schema.authProfiles.user_id, item.created_by),eq(schema.authProfiles.tenant_id,tenant.id))).limit(1))[0];

    console.log(profile)

    const pdfData = getDocumentDataBackend(
        {
            ...item,
            state: "Gebucht",
            documentNumber: documentNumber.usedNumber,
            title: `Rechnung-Nr. ${documentNumber.usedNumber}`,
        }, // Das Dokument (mit neuer Nummer)
        tenant,              // Tenant Object
        customer,            // Customer Object
        contact,             // Contact Object (kann null sein)
        profile,             // User Profile (Contact Person)
        project,             // Project Object
        contract,            // Contract Object
        units,               // Units Array
        products,            // Products Array
        services,            // Services Array
        bankAccounts         // Tenant Bank Accounts
    );


    return pdfData;
}





// Formatiert Zahlen zu deutscher Währung
function renderCurrency(value: any, currency = "€") {
    if (value === undefined || value === null) return "0,00 " + currency;
    return Number(value).toLocaleString("de-DE", {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2
    }) + " " + currency;
}

// Berechnet den Zeilenpreis (Menge * Preis * Rabatt)
function getRowAmount(row: any) {
    const price = Number(row.price || 0);
    const quantity = Number(row.quantity || 0);
    const discount = Number(row.discountPercent || 0);
    return quantity * price * (1 - discount / 100);
}

// Berechnet alle Summen (Netto, Brutto, Steuern, Titel-Summen)
// Dies ersetzt 'documentTotal.value' aus dem Frontend
function calculateDocumentTotals(rows: any[], taxType: string) {
    console.log(rows);

    let totalNet = 0;
    let totalNet19 = 0;
    let totalNet7 = 0;
    let totalNet0 = 0;
    let titleSums: Record<string, number> = {};

    // Aktueller Titel für Gruppierung
    let currentTitle = "";

    rows.forEach(row => {
        if (row.mode === 'title') {
            currentTitle = row.text || row.description || "Titel";
            if (!titleSums[currentTitle]) titleSums[currentTitle] = 0;
            return;
        }

        if (['normal', 'service', 'free'].includes(row.mode)) {
            const amount = getRowAmount(row);
            totalNet += amount;

            // Summen pro Titel addieren
            //if (!titleSums[currentTitle]) titleSums[currentTitle] = 0;
            if(currentTitle.length > 0) titleSums[currentTitle] += amount;

            // Steuer-Logik
            const tax = taxType === "19 UStG" || taxType === "13b UStG" ? 0 : Number(row.taxPercent);

            if (tax === 19) totalNet19 += amount;
            else if (tax === 7) totalNet7 += amount;
            else totalNet0 += amount;
        }
    });

    const isTaxFree = ["13b UStG", "19 UStG"].includes(taxType);

    const tax19 = isTaxFree ? 0 : totalNet19 * 0.19;
    const tax7 = isTaxFree ? 0 : totalNet7 * 0.07;
    const totalGross = totalNet + tax19 + tax7;

    return {
        totalNet,
        totalNet19,
        totalNet7,
        totalNet0,
        total19: tax19,
        total7: tax7,
        total0: 0,
        totalGross,
        titleSums // Gibt ein Objekt zurück: { "Titel A": 150.00, "Titel B": 200.00 }
    };
}

export function getDocumentDataBackend(
    itemInfo: any,       // Das Dokument objekt (createddocument)
    tenant: any,         // Tenant Infos (auth.activeTenantData)
    customerData: any,   // Geladener Kunde
    contactData: any,    // Geladener Kontakt (optional)
    contactPerson: any,  // Geladenes User-Profil (ersetzt den API Call)
    projectData: any,    // Projekt
    contractData: any,   // Vertrag
    units: any[],        // Array aller Einheiten
    products: any[],     // Array aller Produkte
    services: any[],     // Array aller Services
    bankAccounts: any[] = [] // Array aller Bankkonten
) {
    const businessInfo = tenant.businessInfo || {}; // Fallback falls leer
    const paymentQrBankAccount = bankAccounts.find((account: any) => !account.archived && !account.expired && account.iban) || null
    const paymentQrIban = businessInfo.iban || paymentQrBankAccount?.iban
    const paymentQrBic = businessInfo.bic || paymentQrBankAccount?.bic
    const paymentQrRecipient = businessInfo.bankAccountOwner || paymentQrBankAccount?.ownerName || businessInfo.name || tenant.name

    // --- 1. Agriculture Logic ---
    // Prüfen ob 'extraModules' existiert, sonst leeres Array annehmen
    const modules = tenant.extraModules || [];
    if (modules.includes("agriculture")) {
        itemInfo.rows.forEach((row: any) => {
            if (row.agriculture && row.agriculture.dieselUsage) {
                row.agriculture.description = `${row.agriculture.dieselUsage} L Diesel zu ${renderCurrency(row.agriculture.dieselPrice)}/L verbraucht ${row.description ? "\n" + row.description : ""}`;
            }
        });
    }

    // --- 2. Tax Override Logic ---
    let rows = JSON.parse(JSON.stringify(itemInfo.rows)); // Deep Clone um Original nicht zu mutieren
    if (itemInfo.taxType === "13b UStG" || itemInfo.taxType === "19 UStG") {
        rows = rows.map((row: any) => ({ ...row, taxPercent: 0 }));
    }

    // --- 4. Berechnungen (Ersetzt Vue computed props) ---
    const totals = calculateDocumentTotals(rows, itemInfo.taxType);

    console.log(totals);

    // --- 3. Rows Mapping & Processing ---
    rows = rows.map((row: any) => {
        const unit = units.find(i => i.id === row.unit) || { short: "" };

        // Description Text Logic
        if (!['pagebreak', 'title'].includes(row.mode)) {
            if (row.agriculture && row.agriculture.description) {
                row.descriptionText = row.agriculture.description;
            } else if (row.description) {
                row.descriptionText = row.description;
            } else {
                delete row.descriptionText;
            }
        }

        // Product/Service Name Resolution
        if (!['pagebreak', 'title', 'text'].includes(row.mode)) {
            if (row.mode === 'normal') {
                const prod = products.find(i => i.id === row.product);
                if (prod) row.text = prod.name;
            }
            if (row.mode === 'service') {
                const serv = services.find(i => i.id === row.service);
                if (serv) row.text = serv.name;
            }

            const rowAmount = getRowAmount(row);

            return {
                ...row,
                rowAmount: renderCurrency(rowAmount),
                quantity: String(row.quantity).replace(".", ","),
                unit: unit.short,
                pos: String(row.pos),
                price: renderCurrency(row.price),
                discountText: row.discountPercent > 0 ? `(Rabatt: ${row.discountPercent} %)` : ""
            };
        } else {
            return row;
        }
    });



    // --- 5. Handlebars Context ---
    const generateContext = () => {
        return {
            // lohnkosten: null, // Backend hat diesen Wert oft nicht direkt, ggf. aus itemInfo holen
            anrede: (contactData && contactData.salutation) || (customerData && customerData.salutation),
            titel: (contactData && contactData.title) || (customerData && customerData.title),
            vorname: (contactData && contactData.firstName) || (customerData && customerData.firstname), // Achte auf casing (firstName vs firstname) in deiner DB
            nachname: (contactData && contactData.lastName) || (customerData && customerData.lastname),
            kundenname: customerData && customerData.name,
            zahlungsziel_in_tagen: itemInfo.paymentDays,
            zahlungsart: itemInfo.payment_type === "transfer" ? "Überweisung" : "Lastschrift",
            diesel_gesamtverbrauch: (itemInfo.agriculture && itemInfo.agriculture.dieselUsageTotal) || null
        };
    };

    const templateStartText = documentTemplateHandlebars.compile(itemInfo.startText || "");
    const templateEndText = documentTemplateHandlebars.compile(itemInfo.endText || "");

    // --- 6. Title Sums Formatting ---
    let returnTitleSums: Record<string, string> = {};
    Object.keys(totals.titleSums).forEach(key => {
        returnTitleSums[key] = renderCurrency(totals.titleSums[key]);
    });

    // Transfer logic (Falls nötig, hier vereinfacht)
    let returnTitleSumsTransfer = { ...returnTitleSums };

    // --- 7. Construct Final Object ---

    // Adresse aufbereiten
    const recipientArray = [
        customerData.name,
        ...(customerData.nameAddition ? [customerData.nameAddition] : []),
        ...(contactData ? [`${contactData.firstName} ${contactData.lastName}`] : []),
        itemInfo.address?.street || customerData.street || "",
        ...(itemInfo.address?.special ? [itemInfo.address.special] : []),
        `${itemInfo.address?.zip || customerData.zip} ${itemInfo.address?.city || customerData.city}`,
    ].filter(Boolean); // Leere Einträge entfernen

    console.log(contactPerson)

    // Info Block aufbereiten
    const infoBlock = [
        {
            label: itemInfo.documentNumberTitle || "Rechnungsnummer",
            content: itemInfo.documentNumber || "ENTWURF",
        }, {
            label: "Kundennummer",
            content: customerData.customerNumber,
        }, {
            label: "Belegdatum",
            content: itemInfo.documentDate ? dayjs(itemInfo.documentDate).format("DD.MM.YYYY") : dayjs().format("DD.MM.YYYY"),
        },
        // Lieferdatum Logik
        ...(itemInfo.deliveryDateType !== "Kein Lieferdatum anzeigen" ? [{
            label: itemInfo.deliveryDateType || "Lieferdatum",
            content: !['Lieferzeitraum', 'Leistungszeitraum'].includes(itemInfo.deliveryDateType)
                ? (itemInfo.deliveryDate ? dayjs(itemInfo.deliveryDate).format("DD.MM.YYYY") : "")
                : `${itemInfo.deliveryDate ? dayjs(itemInfo.deliveryDate).format("DD.MM.YYYY") : ""} - ${itemInfo.deliveryDateEnd ? dayjs(itemInfo.deliveryDateEnd).format("DD.MM.YYYY") : ""}`,
        }] : []),
        {
            label: "Ansprechpartner",
            content: contactPerson ? (contactPerson.name || contactPerson.full_name || contactPerson.email) : "-",
        },
        // Kontakt Infos
        ...((itemInfo.contactTel || contactPerson?.fixed_tel || contactPerson?.mobile_tel) ? [{
            label: "Telefon",
            content: itemInfo.contactTel || contactPerson?.fixed_tel || contactPerson?.mobile_tel,
        }] : []),
        ...(contactPerson?.email ? [{
            label: "E-Mail",
            content: contactPerson.email,
        }] : []),
        // Objekt / Projekt / Vertrag
        ...(itemInfo.plant ? [{ label: "Objekt", content: "Objekt Name" }] : []), // Hier müsstest du Plant Data übergeben wenn nötig
        ...(projectData ? [{ label: "Projekt", content: projectData.name }] : []),
        ...(contractData ? [{ label: "Vertrag", content: contractData.contractNumber }] : [])
    ];

    // Total Array für PDF Footer
    const totalArray = [
        {
            label: "Nettobetrag",
            content: renderCurrency(totals.totalNet),
        },
        ...(totals.totalNet19 > 0 && !["13b UStG"].includes(itemInfo.taxType) ? [{
            label: `zzgl. 19% USt auf ${renderCurrency(totals.totalNet19)}`,
            content: renderCurrency(totals.total19),
        }] : []),
        ...(totals.totalNet7 > 0 && !["13b UStG"].includes(itemInfo.taxType) ? [{
            label: `zzgl. 7% USt auf ${renderCurrency(totals.totalNet7)}`,
            content: renderCurrency(totals.total7),
        }] : []),
        {
            label: "Gesamtbetrag",
            content: renderCurrency(totals.totalGross),
        },
    ];

    return {
        ...itemInfo,
        type: itemInfo.type,
        taxType: itemInfo.taxType,
        adressLine: `${businessInfo.name || ''}, ${businessInfo.street || ''}, ${businessInfo.zip || ''} ${businessInfo.city || ''}`,
        recipient: recipientArray,
        info: infoBlock,
        title: itemInfo.title,
        description: itemInfo.description,
        // Handlebars Compilation ausführen
        endText: templateEndText(generateContext()),
        startText: templateStartText(generateContext()),
        rows: rows,
        totalArray: totalArray,
        total: {
            totalNet: renderCurrency(totals.totalNet),
            total19: renderCurrency(totals.total19),
            total0: renderCurrency(totals.total0), // 0% USt Zeilen
            totalGross: renderCurrency(totals.totalGross),
            // Diese Werte existieren im einfachen Backend-Kontext oft nicht (Zahlungen checken), daher 0 oder Logik bauen
            totalGrossAlreadyPaid: renderCurrency(0),
            totalSumToPay: renderCurrency(totals.totalGross),
            titleSums: returnTitleSums,
            titleSumsTransfer: returnTitleSumsTransfer
        },
        agriculture: itemInfo.agriculture,
        // Falls du AdvanceInvoices brauchst, musst du die Objekte hier übergeben oder leer lassen
        usedAdvanceInvoices: [],
        paymentQr: paymentQrIban && itemInfo.payment_type === "transfer" ? {
            iban: paymentQrIban,
            bic: paymentQrBic,
            recipientName: paymentQrRecipient,
            amount: totals.totalGross,
            remittance: itemInfo.documentNumber || itemInfo.title,
        } : null
    };
}
