/**
 * Branded LogYou offer (Angebot) PDF builder — pdfmake, server-side.
 * Brand: orange #F15924 / navy #1C324B (from the official logo SVG).
 *
 * Exports the brand constants + header/footer builders separately so the
 * later contract (Vertrag) generator (server/api/offers/contract/*) can
 * reuse the same look without duplicating it.
 */

export const BRAND = {
  orange: '#F15924',
  navy: '#1C324B',
  navySoft: '#2A4560',
  headerSub: '#AFC0D0',
  grayLine: '#E3E7EC',
  grayText: '#5A6B7C',
  zebra: '#F6F8FA',
  text: '#33414E',
  white: '#FFFFFF'
}

export const LEGAL_FOOTER_LINES = [
  'LogYou GmbH · Mühlenweg 4 · 35510 Butzbach  |  Geschäftsführer: Dennis Montag  |  Amtsgericht Friedberg, HRB 10595',
  'Telefon: +49 60 33 / 91 60 57-0  |  Fax: +49 60 33 / 91 60 57-9  |  EMail: info@logyou.de  |  USt-IdNr.: DE 369380129',
  'IBAN: DE 0251 3900 0000 9558 8301  |  Volksbank Mittelhessen'
]

// Every customer-facing string of the quote PDF, per language.
export const QUOTE_TEXTS: any = {
  de: {
    docTitle: 'Fulfillment Angebot',
    dateWord: 'Angebot vom',
    date: 'Datum',
    validUntil: 'Gültig bis',
    plannedStart: 'Geplanter Start',
    version: 'Version',
    intro: 'Vielen Dank für Ihr Interesse. Gerne unterbreiten wir Ihnen folgendes Angebot für Ihr Fulfillment.',
    assumptions: 'Annahmen',
    businessModel: 'Geschäftsmodell',
    shopSystem: 'Shopsystem / Warenwirtschaft',
    avgPicks: 'Ø Picks pro Bestellung',
    ordersPerMonth: 'Ø Bestellungen pro Monat',
    skuCount: 'Ø Gelagerte Artikel (SKUs)',
    storageNeed: 'Lagerbedarf',
    onboarding: 'Onboarding & Setupkosten (IT-Support)',
    free: 'kostenfrei',
    inbound: 'Wareneingang',
    inboundIncluded: 'Warenannahme, Mengenkontrolle & Einlagerung (angemeldet, sortenrein, etikettiert)',
    included: 'im Fulfillment-Preis enthalten',
    inboundExtra: 'Nicht sortenrein / unangemeldet, Etikettierung, Inventur (zzgl. Material)',
    byEffort: 'nach Aufwand*',
    fulfillmentReturns: 'Fulfillment & Retoure',
    service: 'Leistung',
    dimension: 'Dimension',
    price: 'Preis',
    piece: '1 St.',
    time: 'Zeit',
    perMonth: 'pro Monat',
    orderBaseprice: 'Basispreis pro Auftrag',
    orderBasepriceTier: 'Basispreis pro Auftrag (Volumenstufe {n})',
    pickPrice: 'Preis pro Pick',
    pickPriceFrom: 'Preis pro Pick (ab dem {n}. Artikel)',
    customs: 'Zoll-Aufträge (Ausland außerhalb EU) zusätzlich',
    extraWork: 'Zusatzarbeiten (Umpalettieren usw.)',
    palletMove: 'Palette Ein-/Auslagern',
    returnBase: 'Retoure Basispreis',
    returnPerItem: 'Retoure pro Artikel',
    hourlyNote: '*Preis pro Stunde für Arbeiten nach individuellem Aufwand: {rate} pro Stunde, Abrechnung im 5-Minuten-Takt.',
    storageTitle: 'Lagerung (sortenrein)',
    storageType: 'Lagertyp',
    storageSize: 'Größe der Lagerfläche (B×T×H)',
    monthlyCost: 'Monatspreis',
    shelfSmall: 'Fachbodenregal M',
    shelfLarge: 'Fachbodenregal L',
    palletSpace: 'Palettenstellplatz',
    volumeStorage: 'Volumenlagerung',
    perM3: 'pro m³',
    monthlyCosts: 'Monatliche Fulfillment Kosten',
    serviceFee: 'Servicepauschale',
    serviceFeeIncl: 'inkl. Online-Dashboard, Software-Anbindung, Abrechnung & Support',
    packaging: 'Verpackung',
    cartonSize: 'Kartongröße',
    volume: 'Volumen',
    cartonPrice: 'Preis pro Karton',
    paperPrice: 'Packpapier pro Karton',
    individually: 'individuell kalkuliert',
    onRequest: 'auf Anfrage',
    einwegpalette: 'Einwegpalette',
    packagingNote: 'Label und weiteres Verpackungsmaterial nach Verbrauch.',
    shippingTitle: 'Versandkosten National (Deutsche Post / DHL)***',
    shippingMethod: 'Versandart',
    tierKg1: 'Kleinpaket bis 1 kg**',
    tierKg2: 'Paket bis 2 kg*',
    tierKg5: 'Paket bis 5 kg*',
    tierKg10: 'Paket bis 10 kg*',
    tierKg20: 'Paket bis 20 kg*',
    tierKg30: 'Paket bis 31,5 kg*',
    spedition: 'Speditionsversand',
    speditionDefault: 'Tagespreis auf Anfrage',
    forecastTitle: 'Beispielrechnung — Ihre voraussichtlichen monatlichen Kosten',
    fcFulfillment: 'Fulfillment ({orders} Aufträge)',
    fcReturns: 'Retouren (ca. {rate} %)',
    fcStorage: 'Lagerung',
    fcServiceFee: 'Servicepauschale',
    fcPackaging: 'Verpackung (Schätzung Größe {carton})',
    fcShipping: 'Versand (DHL, Annahme bis 2 kg)',
    fcTotal: 'Gesamt pro Monat',
    fcPerOrder: 'Effektiv pro Auftrag',
    fcDisclaimer: 'Unverbindliche Schätzung auf Basis der genannten Annahmen. Abgerechnet wird nach tatsächlichem Verbrauch.',
    notesTitle: 'Hinweise',
    noteVat: 'Alle Preise verstehen sich netto zzgl. 19 % MwSt.',
    noteValidity: 'Das Angebot ist {days} Tage gültig.',
    noteInsurance: '* Versichert bis 500 EUR inkl. Tracking   ** Versichert bis 20 EUR inkl. Tracking   *** Versandpreise sind abhängig vom Frachtdienstleister und können variieren.',
    closing: 'Wir freuen uns auf die Zusammenarbeit!',
    closingTeam: 'Ihr LogYou Team',
    page: 'Seite',
    of: 'von'
  },
  en: {
    docTitle: 'Fulfillment Quote',
    dateWord: 'Quote of',
    date: 'Date',
    validUntil: 'Valid until',
    plannedStart: 'Planned start',
    version: 'Version',
    intro: 'Thank you for your interest. We are pleased to present the following quote for your fulfillment.',
    assumptions: 'Assumptions',
    businessModel: 'Business model',
    shopSystem: 'Shop system / ERP',
    avgPicks: 'Avg. picks per order',
    ordersPerMonth: 'Avg. orders per month',
    skuCount: 'Avg. stored items (SKUs)',
    storageNeed: 'Storage requirement',
    onboarding: 'Onboarding & setup costs (IT support)',
    free: 'free of charge',
    inbound: 'Inbound / Goods receipt',
    inboundIncluded: 'Goods receipt, quantity check & put-away (announced, sorted, labelled)',
    included: 'included in the fulfillment price',
    inboundExtra: 'Unsorted / unannounced goods, labelling, stocktaking (plus material)',
    byEffort: 'by effort*',
    fulfillmentReturns: 'Fulfillment & Returns',
    service: 'Service',
    dimension: 'Dimension',
    price: 'Price',
    piece: '1 pc.',
    time: 'time',
    perMonth: 'per month',
    orderBaseprice: 'Base price per order',
    orderBasepriceTier: 'Base price per order (volume tier {n})',
    pickPrice: 'Price per pick',
    pickPriceFrom: 'Price per pick (from item no. {n})',
    customs: 'Customs orders (outside the EU), additional',
    extraWork: 'Additional work (re-palletizing etc.)',
    palletMove: 'Pallet in-/outbound movement',
    returnBase: 'Return base price',
    returnPerItem: 'Return per item',
    hourlyNote: '*Hourly rate for work billed by individual effort: {rate} per hour, billed in 5-minute increments.',
    storageTitle: 'Storage (sorted by SKU)',
    storageType: 'Storage type',
    storageSize: 'Storage area size (W×D×H)',
    monthlyCost: 'Monthly price',
    shelfSmall: 'Shelf rack M',
    shelfLarge: 'Shelf rack L',
    palletSpace: 'Pallet space',
    volumeStorage: 'Volume storage',
    perM3: 'per m³',
    monthlyCosts: 'Monthly fulfillment costs',
    serviceFee: 'Service fee',
    serviceFeeIncl: 'incl. online dashboard, software integration, billing & support',
    packaging: 'Packaging',
    cartonSize: 'Carton size',
    volume: 'Volume',
    cartonPrice: 'Price per carton',
    paperPrice: 'Packing paper per carton',
    individually: 'calculated individually',
    onRequest: 'on request',
    einwegpalette: 'Disposable pallet',
    packagingNote: 'Labels and further packaging material by consumption.',
    shippingTitle: 'Domestic shipping costs (Deutsche Post / DHL)***',
    shippingMethod: 'Shipping method',
    tierKg1: 'Small parcel up to 1 kg**',
    tierKg2: 'Parcel up to 2 kg*',
    tierKg5: 'Parcel up to 5 kg*',
    tierKg10: 'Parcel up to 10 kg*',
    tierKg20: 'Parcel up to 20 kg*',
    tierKg30: 'Parcel up to 31.5 kg*',
    spedition: 'Freight forwarding',
    speditionDefault: 'daily rate on request',
    forecastTitle: 'Example calculation — your expected monthly costs',
    fcFulfillment: 'Fulfillment ({orders} orders)',
    fcReturns: 'Returns (approx. {rate} %)',
    fcStorage: 'Storage',
    fcServiceFee: 'Service fee',
    fcPackaging: 'Packaging (estimate size {carton})',
    fcShipping: 'Shipping (DHL, assumed up to 2 kg)',
    fcTotal: 'Total per month',
    fcPerOrder: 'Effective per order',
    fcDisclaimer: 'Non-binding estimate based on the stated assumptions. Billing is based on actual consumption.',
    notesTitle: 'Notes',
    noteVat: 'All prices are net plus 19 % German VAT.',
    noteValidity: 'This quote is valid for {days} days.',
    noteInsurance: '* Insured up to EUR 500 incl. tracking   ** Insured up to EUR 20 incl. tracking   *** Shipping prices depend on the carrier and may vary.',
    closing: 'We look forward to working with you!',
    closingTeam: 'Your LogYou team',
    page: 'Page',
    of: 'of'
  }
}

const A4_WIDTH = 595.28

// Authoritative filename — never trust the client's.
export const sanitizeQuoteFilename = (company: string, date?: string): string => {
  const safe = String(company || 'Kunde')
    .replace(/ä/g, 'ae').replace(/ö/g, 'oe').replace(/ü/g, 'ue')
    .replace(/Ä/g, 'Ae').replace(/Ö/g, 'Oe').replace(/Ü/g, 'Ue')
    .replace(/ß/g, 'ss')
    .replace(/[^A-Za-z0-9-_ ]/g, '')
    .trim()
    .replace(/\s+/g, '-') || 'Kunde'
  const d = date || new Date().toISOString().slice(0, 10)
  return `Angebot_LogYou_${safe}_${d}.pdf`
}

// Logos bundled via Nitro server assets (server/assets/offers/*).
let logoCache: { light: string | null; dark: string | null } | null = null
export const getQuoteLogos = async (): Promise<{ light: string | null; dark: string | null }> => {
  if (logoCache) return logoCache
  const storage = useStorage('assets:server')
  const load = async (key: string): Promise<string | null> => {
    try {
      const raw: any = await storage.getItemRaw(key)
      if (!raw) return null
      const buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw)
      return 'data:image/png;base64,' + buf.toString('base64')
    } catch {
      return null
    }
  }
  logoCache = {
    light: await load('offers/logyou-logo.png'),
    dark: await load('offers/logyou-logo-dark.png')
  }
  return logoCache
}

const fmt = (template: string, vars: Record<string, any>): string =>
  template.replace(/\{(\w+)\}/g, (_, k) => String(vars[k] ?? ''))

const formatDateLocal = (iso: string, language: string): string => {
  if (!iso) return '—'
  const d = new Date(iso)
  if (isNaN(d.getTime())) return iso
  const dd = String(d.getDate()).padStart(2, '0')
  const mm = String(d.getMonth() + 1).padStart(2, '0')
  return language === 'en' ? `${d.getFullYear()}-${mm}-${dd}` : `${dd}.${mm}.${d.getFullYear()}`
}

/** Shared branded page header (navy band + logo + orange rule). Reused by the future contract PDF. */
export const buildBrandHeader = (title: string, subtitle: string, logoDarkDataUrl: string | null) => {
  return () => ({
    stack: [
      {
        table: {
          widths: ['*'],
          body: [[{
            border: [false, false, false, false],
            fillColor: BRAND.navy,
            margin: [40, 20, 40, 16],
            columns: [
              logoDarkDataUrl
                ? { image: logoDarkDataUrl, fit: [128, 34], width: 150, margin: [0, 2, 0, 0] }
                : { text: 'LOGYOU', color: BRAND.white, bold: true, fontSize: 20, width: 150, margin: [0, 6, 0, 0] },
              {
                width: '*',
                stack: [
                  { text: title, color: BRAND.white, bold: true, fontSize: 15, alignment: 'right' },
                  { text: subtitle, color: BRAND.headerSub, fontSize: 8, alignment: 'right', margin: [0, 4, 0, 0] }
                ]
              }
            ]
          }]]
        },
        layout: {
          defaultBorder: false,
          paddingLeft: () => 0,
          paddingRight: () => 0,
          paddingTop: () => 0,
          paddingBottom: () => 0
        }
      },
      { canvas: [{ type: 'rect', x: 0, y: 0, w: A4_WIDTH, h: 3, color: BRAND.orange }] }
    ]
  })
}

/** Shared branded page footer (orange hairline + legal lines + page x of y). */
export const buildBrandFooter = (pageWord: string, ofWord: string) => {
  return (currentPage: number, pageCount: number) => ({
    margin: [40, 6, 40, 0],
    stack: [
      { canvas: [{ type: 'line', x1: 0, y1: 0, x2: A4_WIDTH - 80, y2: 0, lineWidth: 0.75, lineColor: BRAND.orange }] },
      ...LEGAL_FOOTER_LINES.map((line, i) => ({
        text: line,
        fontSize: 6.6,
        color: BRAND.grayText,
        alignment: 'center',
        margin: [0, i === 0 ? 5 : 2, 0, 0]
      })),
      { text: `${pageWord} ${currentPage} ${ofWord} ${pageCount}`, fontSize: 6.6, color: BRAND.grayText, alignment: 'right', margin: [0, 2, 0, 0] }
    ]
  })
}

export const buildQuoteDocDefinition = (payload: any, logos: { light: string | null; dark: string | null }) => {
  const language = payload?.meta?.language === 'en' ? 'en' : 'de'
  const T = QUOTE_TEXTS[language]
  const c = payload.customer || {}
  const a = payload.assumptions || {}
  const p = payload.pricing || {}
  const st = a.storage || {}
  const validDays = Number(payload?.meta?.validDays) || 7
  const dateIso = payload?.meta?.date || new Date().toISOString().slice(0, 10)
  const validUntil = new Date(new Date(dateIso).getTime() + validDays * 86400000).toISOString().slice(0, 10)

  const euro = (amount: any) =>
    new Intl.NumberFormat(language === 'en' ? 'en-IE' : 'de-DE', { style: 'currency', currency: 'EUR' }).format(Number(amount) || 0)

  const sectionTitle = (text: string) => ({
    stack: [
      { canvas: [{ type: 'rect', x: 0, y: 0, w: 26, h: 3, color: BRAND.orange }] },
      { text: String(text).toUpperCase(), fontSize: 11, bold: true, color: BRAND.navy, characterSpacing: 0.4, margin: [0, 5, 0, 0] }
    ],
    margin: [0, 16, 0, 8]
  })

  const zebraLayout = {
    hLineWidth: (i: number) => (i === 1 ? 0.75 : 0),
    vLineWidth: () => 0,
    hLineColor: () => BRAND.grayLine,
    fillColor: (rowIndex: number) => (rowIndex === 0 ? BRAND.navy : rowIndex % 2 === 0 ? BRAND.zebra : null),
    paddingLeft: () => 8,
    paddingRight: () => 8,
    paddingTop: () => 5,
    paddingBottom: () => 5
  }

  const th = (text: string, alignment: string = 'left') => ({ text, style: 'tableHeader', alignment })
  const td = (text: any, opts: any = {}) => ({ text: String(text), fontSize: 9, ...opts })
  const tdPrice = (value: any) => td(typeof value === 'number' ? euro(value) : value, { alignment: 'right', bold: typeof value === 'number' })

  const priceTable = (widths: any[], headers: any[], rows: any[][]) => ({
    table: { headerRows: 1, widths, body: [headers, ...rows] },
    layout: zebraLayout
  })

  // Storage-need summary string for the assumptions grid
  const storageParts: string[] = []
  if (Number(st.shelfSmallQty) > 0) storageParts.push(`${st.shelfSmallQty}× ${T.shelfSmall}`)
  if (Number(st.shelfLargeQty) > 0) storageParts.push(`${st.shelfLargeQty}× ${T.shelfLarge}`)
  if (Number(st.palletQty) > 0) storageParts.push(`${st.palletQty}× ${T.palletSpace}`)
  if (Number(st.volumeM3) > 0) storageParts.push(`${st.volumeM3} m³`)
  const storageSummary = storageParts.length ? storageParts.join(', ') : '—'

  const kv = (label: string, value: any) => [
    td(label, { color: BRAND.grayText }),
    td(value || '—', { bold: true })
  ]

  // FULFILLMENT & RETOURE rows (tier rows only when > 0)
  const pickfree = Number(p.qtyPickfree) || 0
  const pickLabel = pickfree > 0 ? fmt(T.pickPriceFrom, { n: pickfree + 1 }) : T.pickPrice
  const fulfillmentRows: any[][] = [
    [td(T.orderBaseprice), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.orderBaseprice))]
  ]
  if (Number(p.orderBaseprice2) > 0) fulfillmentRows.push([td(fmt(T.orderBasepriceTier, { n: 2 })), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.orderBaseprice2))])
  if (Number(p.orderBaseprice3) > 0) fulfillmentRows.push([td(fmt(T.orderBasepriceTier, { n: 3 })), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.orderBaseprice3))])
  fulfillmentRows.push(
    [td(pickLabel), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.orderPickprice))],
    [td(T.customs), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.customsSurcharge))],
    [td(T.extraWork), td(T.time, { alignment: 'center' }), tdPrice(T.byEffort)],
    [td(T.palletMove), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.palletMovePrice))],
    [td(T.returnBase), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.returnBaseprice))],
    [td(T.returnPerItem), td(T.piece, { alignment: 'center' }), tdPrice(Number(p.returnPickprice))]
  )

  // LAGERUNG rows
  const storageRows: any[][] = [
    [td(T.shelfSmall), td('45 × 60 × 40 cm', { alignment: 'center' }), tdPrice(Number(p.shelfSmallPrice))],
    [td(T.shelfLarge), td('90 × 60 × 40 cm', { alignment: 'center' }), tdPrice(Number(p.shelfLargePrice))],
    [td(T.palletSpace), td('120 × 80 × 150 cm', { alignment: 'center' }), tdPrice(Number(p.palletPrice))]
  ]
  if (Number(p.volumeM3Price) > 0) storageRows.push([td(T.volumeStorage), td(T.perM3, { alignment: 'center' }), tdPrice(Number(p.volumeM3Price))])

  // VERPACKUNG rows
  const cartons = p.cartons || {}
  const cartonRow = (label: string, vol: string, key: string) => [
    td(label),
    td(vol, { alignment: 'center' }),
    tdPrice(Number(cartons[key]?.price)),
    tdPrice(Number(cartons[key]?.paper))
  ]
  const packagingRows: any[][] = [
    cartonRow('S', '< 6 l', 's'),
    cartonRow('M', '< 15 l', 'm'),
    cartonRow('L', '< 30 l', 'l'),
    cartonRow('XL', '< 60 l', 'xl'),
    [td('XXL'), td('> 60 l', { alignment: 'center' }), td(T.individually, { alignment: 'right', italics: true, color: BRAND.grayText }), td(T.individually, { alignment: 'right', italics: true, color: BRAND.grayText })],
    [td(T.einwegpalette), td('—', { alignment: 'center' }), tdPrice(Number(p.einwegpalettePrice)), td('—', { alignment: 'right' })]
  ]

  // VERSAND rows
  const tiers = p.dhlTiers || {}
  const shippingRows: any[][] = [
    [td(T.tierKg1), tdPrice(Number(tiers.kg1))],
    [td(T.tierKg2), tdPrice(Number(tiers.kg2))],
    [td(T.tierKg5), tdPrice(Number(tiers.kg5))],
    [td(T.tierKg10), tdPrice(Number(tiers.kg10))],
    [td(T.tierKg20), tdPrice(Number(tiers.kg20))],
    [td(T.tierKg30), tdPrice(Number(tiers.kg30))],
    [td(T.spedition), td(p.speditionNote || T.speditionDefault, { alignment: 'right', italics: true })]
  ]

  const content: any[] = [
    // Address + meta card
    {
      columns: [
        {
          width: '*',
          stack: [
            { text: c.company || '', bold: true, fontSize: 12, color: BRAND.navy },
            { text: c.contactName || '', margin: [0, 3, 0, 0] },
            ...(c.street ? [{ text: c.street, margin: [0, 1, 0, 0] }] : []),
            ...((c.zip || c.city) ? [{ text: [c.zip, c.city].filter(Boolean).join(' '), margin: [0, 1, 0, 0] }] : []),
            { text: c.country || 'Deutschland', margin: [0, 1, 0, 0] }
          ]
        },
        {
          width: 200,
          table: {
            widths: [86, '*'],
            body: [
              kv(T.date, formatDateLocal(dateIso, language)),
              kv(T.validUntil, formatDateLocal(validUntil, language)),
              kv(T.plannedStart, formatDateLocal(a.plannedStart, language))
            ]
          },
          layout: {
            hLineWidth: () => 0,
            vLineWidth: () => 0,
            fillColor: () => BRAND.zebra,
            paddingLeft: () => 8,
            paddingRight: () => 8,
            paddingTop: () => 4,
            paddingBottom: () => 4
          }
        }
      ],
      columnGap: 24,
      margin: [0, 4, 0, 0]
    },
    { text: T.intro, color: BRAND.grayText, margin: [0, 14, 0, 0] },

    // ANNAHMEN
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.assumptions),
        {
          table: {
            widths: [150, '*', 150, '*'],
            body: [
              [...kv(T.businessModel, a.businessModel), ...kv(T.plannedStart, formatDateLocal(a.plannedStart, language))],
              [...kv(T.shopSystem, a.shopSystem), ...kv(T.avgPicks, a.avgPicksPerOrder)],
              [...kv(T.ordersPerMonth, a.ordersPerMonth), ...kv(T.skuCount, a.skuCount)],
              [...kv(T.storageNeed, storageSummary), ...kv(T.onboarding, T.free)]
            ]
          },
          layout: {
            hLineWidth: (i: number) => (i > 0 && i < 4 ? 0.5 : 0),
            vLineWidth: () => 0,
            hLineColor: () => BRAND.grayLine,
            paddingLeft: () => 4,
            paddingRight: () => 8,
            paddingTop: () => 4,
            paddingBottom: () => 4
          }
        }
      ]
    },

    // WARENEINGANG
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.inbound),
        priceTable(
          ['*', 150],
          [th(T.service), th(T.price, 'right')],
          [
            [td(T.inboundIncluded), td(T.included, { alignment: 'right', italics: true })],
            [td(T.inboundExtra), td(T.byEffort, { alignment: 'right', italics: true })]
          ]
        )
      ]
    },

    // FULFILLMENT & RETOURE
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.fulfillmentReturns),
        priceTable(['*', 70, 110], [th(T.service), th(T.dimension, 'center'), th(T.price, 'right')], fulfillmentRows),
        { text: fmt(T.hourlyNote, { rate: euro(Number(p.hourlyRate)) }), fontSize: 7.5, color: BRAND.grayText, margin: [0, 5, 0, 0] }
      ]
    },

    // LAGERUNG
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.storageTitle),
        priceTable(['*', 170, 110], [th(T.storageType), th(T.storageSize, 'center'), th(T.monthlyCost, 'right')], storageRows)
      ]
    },

    // MONATLICHE KOSTEN
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.monthlyCosts),
        priceTable(
          ['*', 110],
          [th(T.service), th(T.price, 'right')],
          [[
            { stack: [td(T.serviceFee, { bold: true }), td(T.serviceFeeIncl, { fontSize: 7.5, color: BRAND.grayText, margin: [0, 2, 0, 0] })] },
            tdPrice(Number(p.monthlyFee))
          ]]
        )
      ]
    },

    // VERPACKUNG
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.packaging),
        priceTable(
          ['*', 80, 110, 120],
          [th(T.cartonSize), th(T.volume, 'center'), th(T.cartonPrice, 'right'), th(T.paperPrice, 'right')],
          packagingRows
        ),
        { text: T.packagingNote, fontSize: 7.5, color: BRAND.grayText, margin: [0, 5, 0, 0] }
      ]
    },

    // VERSAND
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.shippingTitle),
        priceTable(['*', 130], [th(T.shippingMethod), th(T.price, 'right')], shippingRows)
      ]
    }
  ]

  // Optional forecast section
  if (payload?.forecast?.includeInPdf && Array.isArray(payload?.forecast?.lines)) {
    const fc = payload.forecast
    const fcLabel: Record<string, string> = {
      fulfillment: fmt(T.fcFulfillment, { orders: a.ordersPerMonth }),
      returns: fmt(T.fcReturns, { rate: a.returnRatePct }),
      storage: T.fcStorage,
      serviceFee: T.fcServiceFee,
      packaging: fmt(T.fcPackaging, { carton: String(a.typicalCarton || 'M').toUpperCase() }),
      shipping: T.fcShipping
    }
    const fcRows: any[][] = fc.lines.map((line: any) => [td(fcLabel[line.key] || line.key), tdPrice(Number(line.monthly))])
    fcRows.push([
      { text: T.fcTotal, bold: true, fontSize: 10, color: BRAND.white, fillColor: BRAND.navy },
      { text: euro(Number(fc.totalMonthly)), bold: true, fontSize: 10, color: BRAND.orange, alignment: 'right', fillColor: BRAND.navy }
    ])
    fcRows.push([td(T.fcPerOrder, { bold: true }), tdPrice(Number(fc.perOrder))])
    content.push({
      unbreakable: true,
      stack: [
        sectionTitle(T.forecastTitle),
        priceTable(['*', 130], [th(T.service), th(T.price, 'right')], fcRows),
        { text: T.fcDisclaimer, fontSize: 7.5, italics: true, color: BRAND.grayText, margin: [0, 5, 0, 0] }
      ]
    })
  }

  // Notes + closing
  content.push({
    unbreakable: true,
    stack: [
      sectionTitle(T.notesTitle),
      {
        ul: [
          { text: T.noteVat },
          { text: fmt(T.noteValidity, { days: validDays }) },
          { text: fmt(T.hourlyNote, { rate: euro(Number(p.hourlyRate)) }).replace(/^\*/, '') },
          { text: T.noteInsurance }
        ],
        fontSize: 8,
        color: BRAND.grayText,
        markerColor: BRAND.orange
      },
      {
        columns: [
          { width: 'auto', canvas: [{ type: 'rect', x: 0, y: 2, w: 3, h: 26, color: BRAND.orange }] },
          {
            width: '*',
            stack: [
              { text: T.closing, bold: true, fontSize: 11, color: BRAND.navy },
              { text: T.closingTeam, fontSize: 9.5, color: BRAND.grayText, margin: [0, 3, 0, 0] }
            ],
            margin: [10, 0, 0, 0]
          }
        ],
        margin: [0, 18, 0, 0]
      }
    ]
  })

  return {
    pageSize: 'A4',
    pageMargins: [40, 106, 40, 86],
    info: {
      title: `${T.docTitle} – ${c.company || ''}`,
      author: 'LogYou GmbH',
      subject: T.docTitle
    },
    header: buildBrandHeader(T.docTitle, `logyou.de  ·  ${T.dateWord} ${formatDateLocal(dateIso, language)}`, logos.dark),
    footer: buildBrandFooter(T.page, T.of),
    content,
    styles: {
      tableHeader: { fontSize: 8.5, bold: true, color: BRAND.white }
    },
    defaultStyle: {
      font: 'Roboto',
      fontSize: 9.5,
      color: BRAND.text,
      lineHeight: 1.25
    }
  }
}

/** Build the final PDF buffer + authoritative filename. */
export const generateQuotePdf = async (payload: any): Promise<{ buffer: Buffer; filename: string }> => {
  // Import pdfmake with virtual file system for server-side use
  // (defensive vfs extraction copied from generate-fee-report.post.ts — the
  // export shape varies by pdfmake version/bundler, do not simplify).
  const pdfMake = await import('pdfmake/build/pdfmake.js')
  const pdfFonts = await import('pdfmake/build/vfs_fonts.js')

  // @ts-ignore - Set up virtual file system
  const pdfMakeInstance = pdfMake.default || pdfMake

  let vfs = null
  if ((pdfFonts as any).pdfMake?.vfs) {
    vfs = (pdfFonts as any).pdfMake.vfs
  } else if ((pdfFonts as any).default?.pdfMake?.vfs) {
    vfs = (pdfFonts as any).default.pdfMake.vfs
  } else if ((pdfFonts as any).default?.vfs) {
    vfs = (pdfFonts as any).default.vfs
  } else if ((pdfFonts as any).vfs) {
    vfs = (pdfFonts as any).vfs
  } else if ((pdfFonts as any).default) {
    const defaultKeys = Object.keys((pdfFonts as any).default)
    if (defaultKeys.some((key: string) => key.endsWith('.ttf'))) {
      vfs = (pdfFonts as any).default
    }
  }
  if (!vfs) {
    throw new Error('Could not find vfs fonts in pdfmake fonts module')
  }
  pdfMakeInstance.vfs = vfs

  const logos = await getQuoteLogos()
  const docDefinition = buildQuoteDocDefinition(payload, logos)
  const filename = sanitizeQuoteFilename(payload?.customer?.company, payload?.meta?.date)

  const buffer = await new Promise<Buffer>((resolve, reject) => {
    try {
      pdfMakeInstance.createPdf(docDefinition).getBuffer((buf: Buffer) => resolve(buf))
    } catch (error) {
      reject(error)
    }
  })
  return { buffer, filename }
}
