/**
 * Initial-call questionnaire PDF (pdf-lib), DE/EN, multi-page.
 *
 * Two modes from ONE layout:
 *   blank  → every answer is a NATIVE AcroForm field (text fields + check boxes),
 *            so the sheet can be printed and filled by hand OR completed in a PDF
 *            viewer. Company/contact are prefilled from the lead.
 *   filled → answers are drawn as text / ticked boxes, no form fields (final
 *            document that is attached to the lead).
 *
 * Question catalog + answer helpers: app/utils/leadQuestionnaire.ts (shared
 * with the modal). Branding mirrors sepaPdf.ts (logo, navy/orange, legal footer).
 * Standard Helvetica (WinAnsi) — exotic glyphs mapped by `winAnsi()`.
 */
import { PDFDocument, StandardFonts, rgb, type PDFFont, type PDFPage } from 'pdf-lib'
import { getQuoteLogos, LEGAL_FOOTER_LINES } from './quotePdf'
import { parseDataUrl } from './pdfImages'
import { QUESTIONNAIRE, qLabel, formatQuestionnaireAnswer, type QLang, type QQuestion } from '../../../app/utils/leadQuestionnaire'

const A4: [number, number] = [595.28, 841.89]
const M = 48
const NAVY = rgb(0.11, 0.196, 0.294)
const ORANGE = rgb(0.945, 0.349, 0.141)
const GRAY = rgb(0.45, 0.5, 0.55)
const LINE = rgb(0.8, 0.83, 0.87)
const FIELD_BG = rgb(0.955, 0.965, 0.98)
const BAND = rgb(0.93, 0.95, 0.97)
const TEXT = rgb(0.13, 0.16, 0.2)
const WHITE = rgb(1, 1, 1)

const winAnsi = (s: any) => String(s ?? '')
  .replace(/→/g, '->').replace(/—/g, '-').replace(/–/g, '-')
  .replace(/…/g, '...').replace(/[‘’]/g, "'").replace(/[“”„]/g, '"')
  .replace(/[^\x00-\xFF€]/g, '?')

const wrap = (text: string, font: PDFFont, size: number, maxWidth: number): string[] => {
  const out: string[] = []
  for (const para of String(text || '').split('\n')) {
    const words = para.split(/\s+/).filter(Boolean)
    if (!words.length) { out.push(''); continue }
    let line = ''
    for (const w of words) {
      const probe = line ? `${line} ${w}` : w
      if (font.widthOfTextAtSize(probe, size) <= maxWidth) { line = probe; continue }
      if (line) out.push(line)
      line = w
    }
    if (line) out.push(line)
  }
  return out
}

export interface QuestionnaireMeta {
  company?: string
  contactName?: string
  email?: string
  phone?: string
  /** Employee who conducted the call. */
  interviewer?: string
  /** ISO date or human date of the conversation. */
  date?: string
  /** 'phone' | 'meeting' | 'video' | '' */
  channel?: string
}

export interface QuestionnairePdfOptions {
  language: QLang
  mode: 'blank' | 'filled'
  meta?: QuestionnaireMeta
  answers?: Record<string, any>
}

const T = {
  de: {
    title: 'Erstgespräch – Fragebogen',
    subtitle: 'Fulfillment-Bedarfsanalyse für Neukunden',
    company: 'Firma', contact: 'Ansprechpartner', date: 'Datum', channel: 'Gesprächsart', interviewer: 'Gespräch geführt von (LogYou)',
    yes: 'Ja', no: 'Nein',
    channels: { phone: 'Telefon', meeting: 'Persönlich', video: 'Video-Call' } as Record<string, string>,
    page: (n: number, total: number) => `Seite ${n} von ${total}`,
    intro: 'Bitte alle zutreffenden Felder ausfüllen bzw. ankreuzen. Dieser Bogen dient als Grundlage für Angebot und Onboarding.',
    fillHint: 'Ausfüllbares PDF – am Bildschirm oder handschriftlich ausfüllen.'
  },
  en: {
    title: 'Initial call – Questionnaire',
    subtitle: 'Fulfilment needs assessment for new clients',
    company: 'Company', contact: 'Contact person', date: 'Date', channel: 'Type of conversation', interviewer: 'Conducted by (LogYou)',
    yes: 'Yes', no: 'No',
    channels: { phone: 'Phone', meeting: 'In person', video: 'Video call' } as Record<string, string>,
    page: (n: number, total: number) => `Page ${n} of ${total}`,
    intro: 'Please complete or tick all applicable fields. This sheet is the basis for the quote and the onboarding.',
    fillHint: 'Fillable PDF – complete on screen or by hand.'
  }
}

export const buildQuestionnairePdf = async (opts: QuestionnairePdfOptions): Promise<Buffer> => {
  const lang: QLang = opts.language === 'en' ? 'en' : 'de'
  const t = T[lang]
  const filled = opts.mode === 'filled'
  const meta: QuestionnaireMeta = opts.meta || {}
  const answers: Record<string, any> = opts.answers || {}

  const pdf = await PDFDocument.create()
  pdf.setTitle(`${t.title}${meta.company ? ` – ${meta.company}` : ''}`)
  pdf.setAuthor('LogYou GmbH')
  pdf.setLanguage(lang === 'en' ? 'en-GB' : 'de-DE')
  const font = await pdf.embedFont(StandardFonts.Helvetica)
  const bold = await pdf.embedFont(StandardFonts.HelveticaBold)
  const form = pdf.getForm()
  const W = A4[0]
  const contentW = W - 2 * M
  const bottomLimit = M + 34   // legal footer + page number live below this
  let logoImg: any = null
  try {
    const logos = await getQuoteLogos()
    const src = logos.light ? parseDataUrl(logos.light) : null
    if (src?.buffer) logoImg = await pdf.embedPng(src.buffer)
  } catch { /* logo optional */ }

  let page: PDFPage = pdf.addPage(A4)
  let y = A4[1] - M
  let fieldSeq = 0

  const text = (s: string, x: number, yy: number, size: number, f: PDFFont = font, color = TEXT) => {
    page.drawText(winAnsi(s), { x, y: yy, size, font: f, color })
  }
  const newPage = () => {
    page = pdf.addPage(A4)
    y = A4[1] - M
    // small running header on continuation pages
    text(t.title, M, y - 8, 8, bold, GRAY)
    if (meta.company) text(winAnsi(meta.company), W - M - font.widthOfTextAtSize(winAnsi(meta.company), 8), y - 8, 8, font, GRAY)
    y -= 18
    page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 0.5, color: LINE })
    y -= 14
  }
  const ensure = (h: number) => { if (y - h < bottomLimit) newPage() }

  // ---- widgets ------------------------------------------------------------
  /** Text box: blank → AcroForm text field; filled → drawn value. */
  const textBox = (name: string, x: number, yy: number, w: number, h: number, value: string, multiline = false) => {
    page.drawRectangle({ x, y: yy - h, width: w, height: h, color: FIELD_BG, borderColor: LINE, borderWidth: 0.6 })
    if (!filled) {
      const tf = form.createTextField(`q.${name}.${fieldSeq++}`)
      if (multiline) tf.enableMultiline()
      tf.addToPage(page, { x: x + 1, y: yy - h + 1, width: w - 2, height: h - 2, borderWidth: 0, backgroundColor: FIELD_BG, textColor: TEXT, font })
      tf.setFontSize(9)   // after addToPage: the widget's /DA entry must exist first
      tf.setText(winAnsi(value || ''))
      return
    }
    if (!value) return
    const size = 9
    const lines = wrap(winAnsi(value), font, size, w - 10)
    const maxLines = Math.max(1, Math.floor((h - 6) / (size * 1.3)))
    let ty = yy - 4 - size
    for (const l of lines.slice(0, maxLines)) { text(l, x + 5, ty, size, font, TEXT); ty -= size * 1.3 }
  }
  /** Check box (11pt): blank → AcroForm check box; filled → drawn box + tick. */
  const checkBox = (name: string, x: number, yy: number, checked: boolean) => {
    const s = 10.5
    if (!filled) {
      const cb = form.createCheckBox(`q.${name}.${fieldSeq++}`)
      cb.addToPage(page, { x, y: yy - s, width: s, height: s, borderWidth: 0.8, borderColor: GRAY, backgroundColor: WHITE })
      if (checked) cb.check()
      return
    }
    page.drawRectangle({ x, y: yy - s, width: s, height: s, color: WHITE, borderColor: GRAY, borderWidth: 0.8 })
    if (checked) {
      page.drawLine({ start: { x: x + 2.2, y: yy - s + 5 }, end: { x: x + 4.4, y: yy - s + 2.4 }, thickness: 1.6, color: ORANGE })
      page.drawLine({ start: { x: x + 4.4, y: yy - s + 2.4 }, end: { x: x + 8.6, y: yy - s + 8.4 }, thickness: 1.6, color: ORANGE })
    }
  }
  /** Inline flow of labelled check boxes, wraps within contentW. Returns height used. */
  const optionRow = (name: string, options: Array<{ key: string; label: string; checked: boolean }>, startY: number): number => {
    const size = 9
    let x = M
    let yy = startY
    let rows = 1
    for (const o of options) {
      const lw = font.widthOfTextAtSize(winAnsi(o.label), size)
      const need = 10.5 + 5 + lw + 16
      if (x + need > W - M && x > M) { x = M; yy -= 16; rows++ }
      checkBox(`${name}.${o.key}`, x, yy, o.checked)
      text(o.label, x + 15, yy - 8.5, size, font, TEXT)
      x += need
    }
    return rows * 16
  }

  // ---- header --------------------------------------------------------------
  if (logoImg) {
    const h = 26
    const w = (logoImg.width / logoImg.height) * h
    page.drawImage(logoImg, { x: W - M - w, y: y - h + 6, width: w, height: h })
  }
  text(t.title, M, y - 14, 17, bold, NAVY)
  y -= 30
  text(t.subtitle, M, y, 9.5, font, ORANGE)
  y -= 10
  page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 1, color: ORANGE })
  y -= 8
  text(filled ? t.intro : t.fillHint, M, y - 6, 7.5, font, GRAY)
  y -= 16

  // meta block: 2 columns × 3 rows
  const colW = (contentW - 16) / 2
  const metaField = (label: string, name: string, x: number, yy: number, w: number, value: string) => {
    text(label.toUpperCase(), x, yy - 7, 6.5, bold, GRAY)
    textBox(name, x, yy - 10, w, 18, value)
  }
  const dateHuman = (() => {
    const d = meta.date ? new Date(meta.date) : new Date()
    return isNaN(d.getTime()) ? String(meta.date || '') : d.toLocaleDateString(lang === 'en' ? 'en-GB' : 'de-DE', { timeZone: 'Europe/Berlin' })
  })()
  metaField(t.company, 'meta.company', M, y, colW, meta.company || '')
  metaField(t.contact, 'meta.contact', M + colW + 16, y, colW, meta.contactName || '')
  y -= 30
  metaField(t.date, 'meta.date', M, y, colW, filled ? dateHuman : (meta.date ? dateHuman : ''))
  metaField(t.interviewer, 'meta.interviewer', M + colW + 16, y, colW, meta.interviewer || '')
  y -= 30
  // channel as check boxes
  text(t.channel.toUpperCase(), M, y - 7, 6.5, bold, GRAY)
  y -= 12
  y -= optionRow('meta.channel', Object.entries(t.channels).map(([key, label]) => ({ key, label, checked: filled && meta.channel === key })), y)
  page.drawLine({ start: { x: M, y }, end: { x: W - M, y }, thickness: 0.5, color: LINE })
  y -= 10

  // ---- categories & questions ----------------------------------------------
  const labelSize = 9
  const questionBlockHeight = (q: QQuestion): number => {
    // rough estimate used for page-break decisions (label + control)
    const labelLines = wrap(winAnsi(qLabel(q, lang)), bold, labelSize, contentW - (q.type === 'bool' ? 120 : 0)).length
    let h = labelLines * 12 + (q.hintDe ? 10 : 0) + 4
    if (q.type === 'text' || q.type === 'number') h += 22
    if (q.type === 'textarea') h += 46
    if (q.type === 'choice' || q.type === 'multi') h += 16 * Math.ceil((q.options || []).length / 4) + 4
    if (q.detail) h += 24
    return h + 5
  }

  for (const cat of QUESTIONNAIRE) {
    ensure(24 + Math.min(questionBlockHeight(cat.questions[0]), 48))
    // category band
    page.drawRectangle({ x: M, y: y - 16, width: contentW, height: 18, color: BAND })
    page.drawRectangle({ x: M, y: y - 16, width: 3, height: 18, color: ORANGE })
    text(qLabel(cat, lang), M + 10, y - 11, 9.5, bold, NAVY)
    y -= 24

    for (const q of cat.questions) {
      ensure(questionBlockHeight(q))
      const label = qLabel(q, lang)
      const hint = lang === 'en' ? q.hintEn : q.hintDe
      const value = filled ? formatQuestionnaireAnswer({ ...q, detail: undefined }, answers, lang) : ''
      const detailVal = q.detail ? String(answers?.[`${q.id}_detail`] ?? '').trim() : ''

      if (q.type === 'bool') {
        // label left, Ja/Nein boxes right-aligned on the first line
        const lines = wrap(winAnsi(label), bold, labelSize, contentW - 125)
        const v = answers?.[q.id]
        const bx = W - M - 110
        checkBox(`${q.id}.yes`, bx, y, filled && v === true)
        text(t.yes, bx + 15, y - 8.5, 9, font, TEXT)
        checkBox(`${q.id}.no`, bx + 58, y, filled && v === false)
        text(t.no, bx + 73, y - 8.5, 9, font, TEXT)
        let ly = y - 8.5
        for (const l of lines) { text(l, M, ly, labelSize, bold, TEXT); ly -= 12 }
        y = ly + 12 - 12
        if (hint) { text(hint, M, y - 2, 7.5, font, GRAY); y -= 10 }
        if (q.detail) {
          y -= 4
          text(qLabel(q.detail, lang).toUpperCase(), M, y - 7, 6.5, bold, GRAY)
          textBox(`${q.id}.detail`, M, y - 10, contentW, 18, detailVal)
          y -= 30
        }
        y -= 5
        continue
      }

      // label (+ hint)
      const lines = wrap(winAnsi(label), bold, labelSize, contentW)
      let ly = y - 8.5
      for (const l of lines) { text(l, M, ly, labelSize, bold, TEXT); ly -= 12 }
      y = ly + 12 - 12
      if (hint) { text(hint, M, y - 2, 7.5, font, GRAY); y -= 10 }
      y -= 3

      if (q.type === 'text' || q.type === 'number') {
        const w = q.type === 'number' ? Math.min(contentW, 200) : contentW
        textBox(q.id, M, y, w, 18, value)
        if (q.type === 'number' && !filled && q.unit && !q.unitChoice) text(q.unit.replace('Monat', lang === 'en' ? 'month' : 'Monat'), M + w + 6, y - 12.5, 8.5, font, GRAY)
        if (q.type === 'number' && q.unitChoice) {
          // unit picker next to the number box
          let x = M + w + 12
          for (const o of q.unitChoice) {
            const l = qLabel(o, lang)
            checkBox(`${q.id}.unit.${o.key}`, x, y - 3.5, filled ? answers?.[`${q.id}_unit`] === o.key : false)
            text(l, x + 15, y - 12, 8.5, font, TEXT)
            x += 15 + font.widthOfTextAtSize(winAnsi(l), 8.5) + 14
          }
        }
        y -= 20
      } else if (q.type === 'textarea') {
        // The free-notes box (last question) grows to the rest of its page — room for
        // hand-written notes on the printed form, and no near-empty trailing page.
        const h = q.id === 'notes' ? Math.max(42, Math.min(y - bottomLimit - 6, 420)) : 42
        textBox(q.id, M, y, contentW, h, value, true)
        y -= h + 4
      } else if (q.type === 'choice' || q.type === 'multi') {
        const v = answers?.[q.id]
        const opts = (q.options || []).map((o) => ({
          key: o.key,
          label: qLabel(o, lang),
          checked: filled && (q.type === 'multi' ? Array.isArray(v) && v.includes(o.key) : v === o.key)
        }))
        y -= optionRow(q.id, opts, y) - 2
      }

      if (q.detail) {
        ensure(30)
        text(qLabel(q.detail, lang).toUpperCase(), M, y - 7, 6.5, bold, GRAY)
        textBox(`${q.id}.detail`, M, y - 10, contentW, 18, detailVal)
        y -= 30
      }
      y -= 5
    }
    y -= 2
  }

  // ---- footer on every page (legal lines + page number) ----------------------
  const pages = pdf.getPages()
  pages.forEach((p, i) => {
    let fyy = M - 8
    for (const line of [...LEGAL_FOOTER_LINES].reverse()) {
      p.drawText(winAnsi(line), { x: M, y: fyy, size: 6.5, font, color: GRAY })
      fyy += 9
    }
    p.drawLine({ start: { x: M, y: fyy + 2 }, end: { x: W - M, y: fyy + 2 }, thickness: 0.5, color: LINE })
    const pn = t.page(i + 1, pages.length)
    p.drawText(winAnsi(pn), { x: W - M - font.widthOfTextAtSize(pn, 6.5), y: M - 8, size: 6.5, font, color: GRAY })
  })

  if (!filled) form.updateFieldAppearances(font)
  return Buffer.from(await pdf.save())
}
