/**
 * Branded LogYou contract (Fulfillment-Rahmenvertrag) PDF builder.
 * Layout/brand components (BRAND, header, footer, logos) are reused from
 * quotePdf.ts; all legal wording lives in contractTexts.ts.
 */
import { BRAND, buildBrandHeader, buildBrandFooter, getQuoteLogos } from './quotePdf'
import { CONTRACT_TEXTS } from './contractTexts'

const fmt = (template: string, vars: Record<string, any>): string =>
  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()}`
}

export const sanitizeContractFilename = (company: string, language: 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)
  const prefix = language === 'en' ? 'Contract' : 'Vertrag'
  return `${prefix}_LogYou_${safe}_${d}.pdf`
}

export const buildContractDocDefinition = (payload: any, logos: { light: string | null; dark: string | null }) => {
  const language = payload?.meta?.language === 'en' ? 'en' : 'de'
  const T = CONTRACT_TEXTS[language]
  const c = payload.customer || {}
  const a = payload.assumptions || {}
  const st = a.storage || {}
  const ct = payload.contract || {}
  const dateIso = payload?.meta?.date || new Date().toISOString().slice(0, 10)

  // Placeholder values substituted into the legal texts
  const vars = {
    company: c.company || '',
    offerDate: formatDateLocal(ct.offerDate || dateIso, language),
    noticeMonths: Number(ct.noticeMonths) || 3,
    priceNoticeMonths: Number(ct.priceNoticeMonths) || 2,
    objectionWeeks: Number(ct.objectionWeeks) || 6,
    curePeriodDays: Number(ct.curePeriodDays) || 3,
    cutoffTime: ct.cutoffTime || '14:00',
    shrinkagePct: Number(ct.shrinkagePct) || 1
  }

  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.5, bold: true, color: BRAND.navy, characterSpacing: 0.4, margin: [0, 5, 0, 0], tocItem: true, tocStyle: { fontSize: 9, color: BRAND.text } }
    ],
    margin: [0, 18, 0, 8]
  })

  const renderBlock = (block: any, numberOffset: number = 0): any[] => {
    if (!block) return []
    if (block.t === 'p') {
      return [{ text: fmt(block.text, vars), margin: [0, 0, 0, 7], alignment: 'justify' }]
    }
    if (block.t === 'b') {
      return [{
        ul: block.items.map((item: string) => ({ text: fmt(item, vars), margin: [0, 0, 0, 5] })),
        markerColor: BRAND.orange,
        margin: [0, 0, 0, 7]
      }]
    }
    if (block.t === 'n') {
      // Each clause is individually unbreakable (heading stays with its text),
      // but the LIST is breakable — a fully-unbreakable section taller than one
      // page would be clipped by pdfmake.
      return block.items.map((item: any, idx: number) => ({
        unbreakable: true,
        stack: [
          ...(item.h ? [{ text: `${numberOffset + idx + 1}. ${fmt(item.h, vars)}`, bold: true, color: BRAND.navy, fontSize: 9.5, margin: [0, 0, 0, 2] }] : []),
          { text: item.h ? fmt(item.text, vars) : `${numberOffset + idx + 1}. ${fmt(item.text, vars)}`, alignment: 'justify' }
        ],
        margin: [0, 0, 0, 8]
      }))
    }
    return []
  }

  const renderSection = (section: any): any[] => {
    if (!section?.blocks?.length) return []
    const [first, ...rest] = section.blocks
    // Keep the title together with the first block (or, for numbered lists,
    // only the first clause) so headings never orphan at a page bottom while
    // the section itself stays breakable.
    if (first.t === 'n' && first.items.length > 1) {
      const [firstItem, ...restItems] = first.items
      return [
        { unbreakable: true, stack: [sectionTitle(section.title), ...renderBlock({ t: 'n', items: [firstItem] })] },
        ...renderBlock({ t: 'n', items: restItems }, 1),
        ...rest.flatMap((b: any) => renderBlock(b))
      ]
    }
    return [
      { unbreakable: true, stack: [sectionTitle(section.title), ...renderBlock(first)] },
      ...rest.flatMap((b: any) => renderBlock(b))
    ]
  }

  // ---- Cover ----
  const cover: any[] = [
    { text: T.docTitle, fontSize: 24, bold: true, color: BRAND.navy, alignment: 'center', margin: [0, 60, 0, 4] },
    { text: `${T.dateWord}: ${formatDateLocal(dateIso, language)}`, fontSize: 10, color: BRAND.grayText, alignment: 'center', margin: [0, 0, 0, 50] },
    { text: T.between, fontSize: 10, italics: true, color: BRAND.grayText, alignment: 'center', margin: [0, 0, 0, 10] },
    { text: T.logyouParty, fontSize: 11, bold: true, alignment: 'center' },
    { text: T.logyouRef, fontSize: 9, color: BRAND.grayText, alignment: 'center', margin: [0, 3, 0, 24] },
    { text: T.and, fontSize: 10, italics: true, color: BRAND.grayText, alignment: 'center', margin: [0, 0, 0, 10] },
    { text: c.company || '', fontSize: 12, bold: true, color: BRAND.navy, alignment: 'center' },
    ...(c.contactName ? [{ text: c.contactName + (c.signerPosition ? ` — ${c.signerPosition}` : ''), fontSize: 10, alignment: 'center', margin: [0, 2, 0, 0] }] : []),
    ...(c.street ? [{ text: c.street, fontSize: 10, alignment: 'center', margin: [0, 2, 0, 0] }] : []),
    ...((c.zip || c.city) ? [{ text: [c.zip, c.city].filter(Boolean).join(' '), fontSize: 10, alignment: 'center', margin: [0, 2, 0, 0] }] : []),
    { text: c.country || (language === 'en' ? 'Germany' : 'Deutschland'), fontSize: 10, alignment: 'center', margin: [0, 2, 0, 0] },
    ...(c.ustId ? [{ text: `${T.signatures.vatId}: ${c.ustId}`, fontSize: 9, color: BRAND.grayText, alignment: 'center', margin: [0, 2, 0, 0] }] : []),
    { text: T.customerRef, fontSize: 9, color: BRAND.grayText, alignment: 'center', margin: [0, 3, 0, 0] },
    // Table of contents (native pdfmake TOC with real page numbers)
    {
      toc: { title: { text: T.tocTitle, fontSize: 13, bold: true, color: BRAND.navy, margin: [0, 0, 0, 8] } },
      pageBreak: 'before'
    }
  ]

  // ---- Assumptions (dynamic) ----
  const L = T.assumptions.labels
  const storageUnits = language === 'en'
    ? { small: 'shelf M', large: 'shelf L', pallet: 'pallet space(s)' }
    : { small: 'Fachboden M', large: 'Fachboden L', pallet: 'Palettenstellplatz/-plätze' }
  const storageParts: string[] = []
  if (Number(st.shelfSmallQty) > 0) storageParts.push(`${st.shelfSmallQty}× ${storageUnits.small}`)
  if (Number(st.shelfLargeQty) > 0) storageParts.push(`${st.shelfLargeQty}× ${storageUnits.large}`)
  if (Number(st.palletQty) > 0) storageParts.push(`${st.palletQty}× ${storageUnits.pallet}`)
  if (Number(st.volumeM3) > 0) storageParts.push(`${st.volumeM3} m³`)

  const kvRow = (label: string, value: any) => [
    { text: label, color: BRAND.grayText, fontSize: 9 },
    { text: String(value || '—'), bold: true, fontSize: 9 }
  ]
  const assumptionsSection: any[] = [
    {
      unbreakable: true,
      stack: [
        sectionTitle(T.assumptions.title),
        { text: T.assumptions.intro, margin: [0, 0, 0, 8] },
        {
          table: {
            widths: [210, '*'],
            body: [
              kvRow(L.plannedStart, formatDateLocal(a.plannedStart, language)),
              kvRow(L.businessModel, a.businessModel),
              kvRow(L.shopSystem, a.shopSystem),
              kvRow(L.ordersPerMonth, a.ordersPerMonth),
              kvRow(L.avgPicks, a.avgPicksPerOrder),
              kvRow(L.skuCount, a.skuCount),
              kvRow(L.storage, storageParts.join(', ') || '—')
            ]
          },
          layout: {
            hLineWidth: () => 0,
            vLineWidth: () => 0,
            fillColor: (rowIndex: number) => (rowIndex % 2 === 0 ? BRAND.zebra : null),
            paddingLeft: () => 8,
            paddingRight: () => 8,
            paddingTop: () => 4,
            paddingBottom: () => 4
          },
          margin: [0, 0, 0, 8]
        },
        { text: T.assumptions.onboarding, bold: true, color: BRAND.navy, margin: [0, 2, 0, 8] }
      ]
    },
    { text: fmt(T.assumptions.integration, vars), alignment: 'justify', margin: [0, 0, 0, 7] }
  ]

  // ---- SLA (with optional express clause) ----
  const slaSection = JSON.parse(JSON.stringify(T.sla))
  if (ct.includeExpress) {
    slaSection.blocks[0].items.push(T.sla.express)
  }

  // ---- Payment (method variant) ----
  const paymentSection = {
    title: T.payment.title,
    blocks: [ct.paymentMethod === 'transfer' ? T.payment.transfer : T.payment.sepa, ...T.payment.common]
  }

  // ---- Marketing (variant) ----
  const marketingSection = {
    title: T.marketing.title,
    blocks: [ct.marketingVariant === 'approval' ? T.marketing.approval : T.marketing.consent]
  }

  // ---- Custom special clauses (dynamic) ----
  const customClauses = (ct.customClauses || []).filter((cl: any) => String(cl?.text || '').trim())
  const specialSection: any[] = customClauses.length
    ? [
        { unbreakable: true, stack: [sectionTitle(T.special.title), { text: T.special.intro, margin: [0, 0, 0, 8] }] },
        ...customClauses.map((cl: any, idx: number) => ({
          stack: [
            { text: `${idx + 1}. ${cl.title || (language === 'en' ? 'Supplementary agreement' : 'Sondervereinbarung')}`, bold: true, color: BRAND.navy, fontSize: 9.5, margin: [0, 0, 0, 2] },
            { text: String(cl.text), alignment: 'justify' }
          ],
          margin: [0, 0, 0, 8]
        }))
      ]
    : []

  // ---- Signatures ----
  const S = T.signatures
  const sigLine = (label: string, value: string) => ({
    columns: [
      { text: label, width: 110, color: BRAND.grayText, fontSize: 9 },
      { text: value, width: '*', fontSize: 9.5 }
    ],
    margin: [0, 0, 0, 6]
  })
  const signaturesSection: any[] = [
    {
      unbreakable: true,
      stack: [
        sectionTitle(S.title),
        { text: S.logyouCompany, bold: true, color: BRAND.navy, margin: [0, 6, 0, 2] },
        { text: `${S.logyouCity}, ${formatDateLocal(dateIso, language)}`, fontSize: 9, color: BRAND.grayText, margin: [0, 0, 0, 26] },
        { canvas: [{ type: 'line', x1: 0, y1: 0, x2: 220, y2: 0, lineWidth: 0.75, lineColor: BRAND.grayLine }] },
        { text: `${S.logyouSigner} — ${S.logyouPosition}`, fontSize: 9, margin: [0, 4, 0, 24] },

        { text: S.customerWord, bold: true, color: BRAND.navy, margin: [0, 6, 0, 8] },
        sigLine(S.date, S.dots),
        sigLine(S.signature, S.dots),
        sigLine(S.name, c.contactName || S.dots),
        sigLine(S.position, c.signerPosition || S.dots),
        sigLine(S.company, c.company || S.dots),
        ...(c.ustId ? [sigLine(S.vatId, c.ustId)] : []),
        sigLine(S.address, [c.street, [c.zip, c.city].filter(Boolean).join(' '), c.country].filter(Boolean).join(' / ') || S.dots)
      ]
    }
  ]

  const content: any[] = [
    ...cover,
    { text: '', pageBreak: 'after' },
    ...renderSection(T.master),
    ...renderSection(T.services),
    ...renderSection(T.term),
    ...renderSection(T.pricing),
    ...assumptionsSection,
    ...renderSection(T.adjustments),
    ...renderSection(paymentSection),
    ...renderSection(slaSection),
    ...renderSection(T.liability),
    ...renderSection(T.property),
    ...renderSection(T.compliance),
    ...renderSection(T.privacy),
    ...renderSection(marketingSection),
    ...specialSection,
    ...renderSection(T.jurisdiction),
    ...renderSection(T.final),
    ...renderSection(T.annex),
    ...signaturesSection
  ]

  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.3
    }
  }
}

export const generateContractPdf = async (payload: any): Promise<{ buffer: Buffer; filename: string }> => {
  // Import pdfmake with virtual file system for server-side use
  // (defensive vfs extraction — 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 language = payload?.meta?.language === 'en' ? 'en' : 'de'
  const logos = await getQuoteLogos()
  const docDefinition = buildContractDocDefinition(payload, logos)
  const filename = sanitizeContractFilename(payload?.customer?.company, language, 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 }
}
