// ==================== GUTSCHRIFT-PDF ====================
// Erzeugt ein Gutschrift-PDF (pdfkit) mit den Firmenstammdaten als Absender.
// Rückgabe: Buffer (für ZUGFeRD-Embedding in Teil 2) + gespeicherter Pfad.

import fs from 'fs';
import path from 'path';
import PDFDocument from 'pdfkit';
import prisma from '../lib/prisma.js';
import { ApiError } from '../utils/apiError.js';
import { getOrCreateProfile } from './companyProfile.service.js';
import { effectiveNumber } from './creditNote.service.js';
import { buildZugferdXml } from './zugferd.service.js';
import { embedZugferd } from './zugferdPdf.service.js';

const FONT_DIR = path.join(process.cwd(), 'assets', 'fonts');

function euro(n: number, currency = 'EUR'): string {
  return new Intl.NumberFormat('de-DE', { style: 'currency', currency }).format(n || 0);
}

function ddmmyyyy(d: Date): string {
  return d.toLocaleDateString('de-DE');
}

async function loadData(creditNoteId: number) {
  const cn = await prisma.creditNote.findUnique({
    where: { id: creditNoteId },
    include: {
      contract: {
        include: {
          customer: {
            select: {
              firstName: true, lastName: true, companyName: true, type: true,
              customerNumber: true, vatExempt: true,
            },
          },
          billingAddress: true,
          address: true,
        },
      },
      payoutBankCard: { select: { iban: true, accountHolder: true, bankName: true } },
    },
  });
  if (!cn) throw new ApiError(404, 'Gutschrift nicht gefunden');
  const company = await getOrCreateProfile();
  return { cn, company };
}

export async function generateCreditNotePdf(creditNoteId: number): Promise<{ buffer: Buffer; pdfPath: string; xml: string }> {
  const { cn, company } = await loadData(creditNoteId);
  const customer = cn.contract.customer;
  const addr = cn.contract.billingAddress || cn.contract.address;

  const recipientName =
    customer.type === 'BUSINESS' && customer.companyName
      ? customer.companyName
      : `${customer.firstName} ${customer.lastName}`.trim();

  const doc = new PDFDocument({ size: 'A4', margin: 50 });
  // PDF/A verlangt eingebettete Fonts – DejaVuSans (im Repo) statt der
  // nicht-eingebetteten pdfkit-Standard-Fonts (Helvetica).
  doc.registerFont('Body', path.join(FONT_DIR, 'DejaVuSans.ttf'));
  doc.registerFont('Body-Bold', path.join(FONT_DIR, 'DejaVuSans-Bold.ttf'));
  doc.font('Body');
  const chunks: Buffer[] = [];
  doc.on('data', (c: Buffer) => chunks.push(c));
  const done = new Promise<Buffer>((resolve) => doc.on('end', () => resolve(Buffer.concat(chunks))));

  // ---- Absender (klein, oben) ----
  const senderLine = [
    company.name,
    `${company.street} ${company.houseNumber}`.trim(),
    `${company.postalCode} ${company.city}`.trim(),
  ].filter(Boolean).join(' · ');
  doc.fontSize(8).fillColor('#666').text(senderLine || ' ', 50, 50, { width: 495 });
  doc.fillColor('#000');

  // ---- Empfänger ----
  doc.moveDown(2);
  doc.fontSize(11);
  doc.text(recipientName, { continued: false });
  if (addr) {
    doc.text(`${addr.street} ${addr.houseNumber}`.trim());
    doc.text(`${addr.postalCode} ${addr.city}`.trim());
  }
  doc.fontSize(8).fillColor('#666').text(`Kundennr.: ${customer.customerNumber}`);
  doc.fillColor('#000');

  // ---- Titel + Meta ----
  doc.moveDown(2);
  // Sachwert ohne Betrag = reine Übergabe des Gegenstands als Subvention,
  // KEINE Rechnung (kein Betrag, keine USt, kein ZUGFeRD).
  const nonMonetary = cn.type === 'SACHWERT' && cn.amountGross === 0;

  doc.fontSize(18).text(nonMonetary ? 'Sachwert-Übergabe' : 'Gutschrift', { align: 'left' });
  doc.moveDown(0.3);
  doc.fontSize(10);
  // Belegnummer je nach Typ (Lieferschein- bzw. Gutschriftsnummer).
  const belegNr = effectiveNumber(cn) ?? `#${cn.id}`;
  doc.text(`Nr.: ${belegNr}`);
  doc.text(`Datum: ${ddmmyyyy(new Date(cn.creditDate))}`);

  // ---- Beschreibung / Betrag ----
  doc.moveDown(1.2);
  const description =
    cn.type === 'SACHWERT'
      ? `Sachwert / Subvention: ${cn.sachwertDescription || '—'}`
      : 'Subvention (Auszahlung per Überweisung)';
  doc.fontSize(11).text(description);
  doc.moveDown(0.5);

  const startX = 50;
  const rightX = 545;
  const labelW = 300;
  const line = (label: string, value: string, bold = false) => {
    doc.font(bold ? 'Body-Bold' : 'Body').fontSize(11);
    const y = doc.y;
    doc.text(label, startX, y, { width: labelW });
    doc.text(value, startX, y, { width: rightX - startX, align: 'right' });
    doc.font('Body');
  };

  if (nonMonetary) {
    doc.fontSize(10).fillColor('#333')
      .text('Der Sachwert wurde als Subvention übergeben. Es erfolgt keine Rechnungsstellung / kein Rechnungsbetrag.', startX, doc.y, { width: 495 });
    doc.fillColor('#000');
  } else if (cn.vatRelevant) {
    line('Nettobetrag', euro(cn.amountNet, cn.currency));
    line(`Umsatzsteuer ${cn.vatRate}%`, euro(cn.amountVat, cn.currency));
    doc.moveDown(0.2);
    line('Bruttobetrag', euro(cn.amountGross, cn.currency), true);
  } else {
    line('Betrag', euro(cn.amountGross, cn.currency), true);
    doc.moveDown(0.3);
    doc.fontSize(8).fillColor('#666')
      .text('Ohne gesonderten Umsatzsteuerausweis.', startX, doc.y, { width: 495 });
    doc.fillColor('#000');
  }

  // ---- Typ-spezifisch ----
  doc.moveDown(1.5);
  doc.fontSize(10);
  if (cn.type === 'SACHWERT') {
    doc.text(`Ware erhalten: ${cn.goodsReceived ? 'Ja' : 'Nein'}`);
  } else {
    doc.text('Auszahlung per Überweisung.');
    if (company.iban) {
      doc.fontSize(9).fillColor('#333')
        .text(`Unsere Bankverbindung: ${[company.bankName, `IBAN ${company.iban}`, company.bic ? `BIC ${company.bic}` : ''].filter(Boolean).join(' · ')}`);
    }
    // Auszahlungskonto des Kunden (kann vom Abbuchkonto abweichen).
    if (cn.payoutBankCard) {
      const holder = cn.payoutBankCard.accountHolder ? ` (${cn.payoutBankCard.accountHolder})` : '';
      doc.fontSize(9).fillColor('#333')
        .text(`an Bankkonto: ${cn.payoutBankCard.iban}${holder}${cn.payoutBankCard.bankName ? ` · ${cn.payoutBankCard.bankName}` : ''}`);
    }
    doc.fillColor('#000');
  }

  // ---- Unterschriftsblock ----
  // Nur bei Sachwert: das Dokument wird vom Kunden unterschrieben. Bei einer
  // Geld-Überweisung ist keine Unterschrift nötig – als Beleg dient die
  // hochgeladene Überweisungsbestätigung.
  if (cn.type === 'SACHWERT') {
    doc.moveDown(3);
    const y = doc.y;
    const place = cn.place || company.city || '';
    doc.fontSize(10).fillColor('#000');
    doc.text('_______________________________', 50, y);
    doc.text('_______________________________', 320, y);
    doc.fontSize(8).fillColor('#666');
    doc.text(`Ort/Datum${place ? ` (${place})` : ''}`, 50, y + 14);
    doc.text('Unterschrift', 320, y + 14);
    doc.fillColor('#000');
  }

  // ---- Fußzeile (Firmendaten) ----
  // Position aus der Seitengeometrie berechnen, damit die Fußzeile am
  // unteren Rand der ERSTEN Seite endet und keine zweite Seite auslöst
  // (auch wenn sie zweizeilig umbricht).
  const footerParts = [
    company.name,
    company.managingDirector ? `GF: ${company.managingDirector}` : '',
    company.vatId ? `USt-IdNr: ${company.vatId}` : '',
    company.taxNumber ? `St.-Nr.: ${company.taxNumber}` : '',
    company.commercialRegister,
    company.iban ? `IBAN: ${company.iban}` : '',
  ].filter(Boolean);
  const footerText = footerParts.join(' · ');
  const footerWidth = 495;
  doc.fontSize(7).fillColor('#888');
  const footerHeight = doc.heightOfString(footerText, { width: footerWidth, align: 'center' });
  // Unteren Rand für die Fußzeile kurz verkleinern, damit sie ein Stück
  // tiefer sitzt, ohne dass pdfkit eine zweite Seite anlegt.
  const savedBottom = doc.page.margins.bottom;
  doc.page.margins.bottom = 22;
  const bottomLimit = doc.page.height - doc.page.margins.bottom;
  doc.text(footerText, 50, bottomLimit - footerHeight - 2, { width: footerWidth, align: 'center' });
  doc.page.margins.bottom = savedBottom;
  doc.fillColor('#000');

  doc.end();
  const baseBuffer = await done;

  // Nicht-monetärer Sachwert = keine Rechnung → KEIN ZUGFeRD-Embedding,
  // nur das reine PDF (Empfangs-/Übergabebeleg).
  let xml = '';
  let buffer = baseBuffer;
  if (!nonMonetary) {
    // ---- ZUGFeRD-XML erzeugen + als hybrides PDF/A-3 einbetten ----
    xml = buildZugferdXml({
      number: cn.number ?? '',
      issueDate: new Date(cn.creditDate),
      currency: cn.currency,
      seller: {
        name: company.name,
        street: company.street,
        houseNumber: company.houseNumber,
        postalCode: company.postalCode,
        city: company.city,
        country: company.country || 'DE',
        vatId: company.vatId || undefined,
        taxNumber: company.taxNumber || undefined,
      },
      buyer: {
        name: recipientName,
        street: addr?.street || '',
        houseNumber: addr?.houseNumber || '',
        postalCode: addr?.postalCode || '',
        city: addr?.city || '',
        country: 'DE',
      },
      lineName:
        cn.type === 'SACHWERT'
          ? `Sachwert / Subvention: ${cn.sachwertDescription || ''}`.trim()
          : 'Subvention (Auszahlung per Überweisung)',
      vatRelevant: cn.vatRelevant,
      vatRatePercent: cn.vatRate,
      amountNet: cn.amountNet,
      amountVat: cn.amountVat,
      amountGross: cn.amountGross,
    });

    buffer = await embedZugferd(baseBuffer, xml, {
      title: `Gutschrift ${cn.number ?? ''}`.trim(),
      date: new Date(cn.creditDate),
    });
  }

  // ---- Speichern ----
  const dir = path.join(process.cwd(), 'uploads', 'credit-notes');
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  const filename = `${nonMonetary ? 'lieferschein' : 'gutschrift'}-${(belegNr).replace(/[^A-Za-z0-9_-]/g, '_')}-${cn.id}.pdf`;
  const filepath = path.join(dir, filename);
  fs.writeFileSync(filepath, buffer);
  const pdfPath = `/uploads/credit-notes/${filename}`;

  await prisma.creditNote.update({ where: { id: cn.id }, data: { pdfPath } });

  return { buffer, pdfPath, xml };
}
