// PDF report for the cash-basis GuV / EÜR BI pages (/bi/profit-loss, /bi/income-surplus).
// Client-only jsPDF (A4 landscape), built from the SAME aggregated rows the page
// renders (BI/BankCashReport.vue hands over a plain payload — no re-aggregation
// here). Pages: ① overview (KPI cards + monthly chart drawn natively, no amCharts
// export), ② the month × position report table, ③ top payers / payees with
// share bars. Helvetica (WinAnsi) covers umlauts, € and Ø; avoid Δ / arrows.

export interface BankCashPdfRow {
  kind: 'section' | 'sub' | 'sum' | 'result' | 'row'
  label: string
  values?: number[]
  total?: number
  signed?: boolean
  muted?: boolean
  italic?: boolean
  lineNo?: string
  count?: number
}

export interface BankCashPdfCounterpart { name: string; total: number; count: number }

export interface BankCashPdfPayload {
  variant: 'guv' | 'euer'
  title: string
  year: number
  scope: string
  orgName: string
  dataBasis: string
  locale: string
  generatedAt: Date
  monthShort: string[]
  monthHasData: boolean[]
  futureFrom: number | null          // first month (1..12) that lies in the future, null = none
  kpis: {
    income: number; expense: number; net: number; avgNet: number; activeMonths: number; count: number
    prev: { income: number; expense: number; net: number } | null
  }
  chart: { income: number; expense: number; net: number | null; prevNet: number | null }[]
  rows: BankCashPdfRow[]
  payers: { top: BankCashPdfCounterpart[]; other: BankCashPdfCounterpart | null }
  payees: { top: BankCashPdfCounterpart[]; other: BankCashPdfCounterpart | null }
  transfers: { included: boolean; count: number; amount: number }
  truncated: boolean
  labels: Record<string, string>
}

const PAGE_W = 297
const PAGE_H = 210
const MARGIN = 12
const CONTENT_W = PAGE_W - 2 * MARGIN

// Same palette as BankCashMonthlyChart.vue (light theme) + slate neutrals.
const C = {
  income: [42, 120, 214] as const,
  incomeSoft: [226, 237, 250] as const,
  expense: [235, 104, 52] as const,
  expenseSoft: [252, 234, 226] as const,
  ink: [11, 11, 11] as const,
  text: [52, 51, 48] as const,
  muted: [120, 119, 114] as const,
  grid: [226, 225, 221] as const,
  band: [245, 244, 241] as const,
  accent: [30, 41, 59] as const,
  resultSoft: [236, 240, 246] as const,
  negative: [185, 28, 28] as const,
  white: [255, 255, 255] as const
}
type RGB = readonly [number, number, number]

const fill = (doc: any, c: RGB) => doc.setFillColor(c[0], c[1], c[2])
const stroke = (doc: any, c: RGB) => doc.setDrawColor(c[0], c[1], c[2])
const ink = (doc: any, c: RGB) => doc.setTextColor(c[0], c[1], c[2])
const font = (doc: any, size: number, style: 'normal' | 'bold' | 'italic' | 'bolditalic' = 'normal') => {
  doc.setFont('helvetica', style)
  doc.setFontSize(size)
}

/** Truncate with an ellipsis so the text fits `maxW` mm at the current font. */
const fitText = (doc: any, text: string, maxW: number): string => {
  const s = String(text ?? '')
  if (doc.getTextWidth(s) <= maxW) return s
  let lo = 0
  let hi = s.length
  while (lo < hi) {
    const mid = Math.ceil((lo + hi) / 2)
    if (doc.getTextWidth(s.slice(0, mid) + '…') <= maxW) lo = mid
    else hi = mid - 1
  }
  return s.slice(0, Math.max(0, lo)).trimEnd() + '…'
}

const loadImage = (url: string): Promise<{ dataUrl: string; w: number; h: number } | null> =>
  new Promise(resolve => {
    if (!import.meta.client || typeof Image === 'undefined') return resolve(null)
    const img = new Image()
    img.crossOrigin = 'anonymous'
    img.onload = () => {
      try {
        const canvas = document.createElement('canvas')
        canvas.width = img.naturalWidth
        canvas.height = img.naturalHeight
        canvas.getContext('2d')?.drawImage(img, 0, 0)
        resolve({ dataUrl: canvas.toDataURL('image/png'), w: img.naturalWidth, h: img.naturalHeight })
      } catch { resolve(null) }
    }
    img.onerror = () => resolve(null)
    img.src = url
  })

export const bankCashReportPdfFileName = (variant: string, year: number, accountId?: string | number) =>
  `${variant === 'guv' ? 'guv' : 'euer'}-${year}${accountId ? '-' + accountId : ''}.pdf`

export const buildBankCashReportPdf = async (p: BankCashPdfPayload) => {
  if (!import.meta.client) throw new Error('PDF generation is client-only')
  const { jsPDF } = await import('jspdf')
  const doc = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4', compress: true })
  const L = p.labels
  const money = (v: number | null | undefined, blankZero = false) => {
    const n = Number(v) || 0
    if (blankZero && n === 0) return ''
    return new Intl.NumberFormat(p.locale, { style: 'currency', currency: 'EUR' }).format(n)
  }
  const percent = (v: number, total: number) => total
    ? new Intl.NumberFormat(p.locale, { style: 'percent', minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(v / total)
    : '—'
  const dateTime = new Intl.DateTimeFormat(p.locale, { dateStyle: 'medium', timeStyle: 'short' }).format(p.generatedAt)
  const logo = await loadImage('/assets/logyou-logo-color.png')

  // ---------------------------------------------------------------------------
  // Chrome: header band + footer on every page (page numbers filled at the end)

  const HEADER_H = 22
  const FOOTER_Y = PAGE_H - 9
  const pages: { subtitle: string }[] = []

  const header = (subtitle: string) => {
    pages.push({ subtitle })
    fill(doc, C.accent)
    doc.rect(0, 0, PAGE_W, HEADER_H, 'F')
    fill(doc, C.income)
    doc.rect(0, HEADER_H, PAGE_W, 1.2, 'F')

    ink(doc, C.white)
    font(doc, 15, 'bold')
    doc.text(`${p.title} ${p.year}`, MARGIN, 10)
    font(doc, 9, 'normal')
    doc.setTextColor(200, 208, 222)
    doc.text(subtitle, MARGIN, 16.5)

    let rightEdge = PAGE_W - MARGIN
    if (logo) {
      const h = 9
      const w = h * (logo.w / logo.h)
      // white plate so the colour logo sits cleanly on the dark band
      fill(doc, C.white)
      doc.roundedRect(rightEdge - w - 3, 4.5, w + 6, h + 4, 1.5, 1.5, 'F')
      try { doc.addImage(logo.dataUrl, 'PNG', rightEdge - w, 6.5, w, h, undefined, 'FAST') } catch {}
      rightEdge -= w + 10
    }
    font(doc, 9, 'bold')
    ink(doc, C.white)
    doc.text(fitText(doc, p.orgName || '', 90), rightEdge, 10, { align: 'right' })
    font(doc, 8, 'normal')
    doc.setTextColor(200, 208, 222)
    doc.text(fitText(doc, p.scope, 90), rightEdge, 16.5, { align: 'right' })
  }

  const footers = () => {
    const total = doc.getNumberOfPages()
    for (let i = 1; i <= total; i++) {
      doc.setPage(i)
      stroke(doc, C.grid)
      doc.setLineWidth(0.25)
      doc.line(MARGIN, FOOTER_Y - 3.5, PAGE_W - MARGIN, FOOTER_Y - 3.5)
      font(doc, 7, 'normal')
      ink(doc, C.muted)
      doc.text(fitText(doc, `${L.generated || 'Generated'} ${dateTime} · ${p.dataBasis}`, 200), MARGIN, FOOTER_Y)
      doc.text(`${L.page || 'Page'} ${i} / ${total}`, PAGE_W - MARGIN, FOOTER_Y, { align: 'right' })
    }
  }

  // ---------------------------------------------------------------------------
  // Page 1 — overview

  header(L.overview || 'Overview')
  let y = HEADER_H + 10

  // KPI cards
  const cards = [
    { label: `${L.income} ${p.year}`, value: money(p.kpis.income), sub: p.kpis.prev ? `${p.year - 1}: ${money(p.kpis.prev.income)}` : '', color: C.income, soft: C.incomeSoft },
    { label: `${L.expense} ${p.year}`, value: money(p.kpis.expense), sub: p.kpis.prev ? `${p.year - 1}: ${money(p.kpis.prev.expense)}` : '', color: C.expense, soft: C.expenseSoft },
    { label: `${L.result} ${p.year}`, value: money(p.kpis.net), sub: p.kpis.prev ? `${p.year - 1}: ${money(p.kpis.prev.net)}` : '', color: p.kpis.net < 0 ? C.negative : C.accent, soft: C.resultSoft, signed: true, v: p.kpis.net },
    { label: L.avgMonth || 'Ø result per month', value: money(p.kpis.avgNet), sub: `${p.kpis.activeMonths} ${L.months || 'months'} · ${p.kpis.count} ${L.movements || 'movements'}`, color: p.kpis.avgNet < 0 ? C.negative : C.accent, soft: C.band, signed: true, v: p.kpis.avgNet }
  ]
  const gap = 6
  const cardW = (CONTENT_W - gap * 3) / 4
  const cardH = 26
  cards.forEach((card, i) => {
    const x = MARGIN + i * (cardW + gap)
    fill(doc, card.soft)
    doc.roundedRect(x, y, cardW, cardH, 2, 2, 'F')
    fill(doc, card.color)
    doc.rect(x, y + 3, 1.4, cardH - 6, 'F')
    font(doc, 8, 'normal')
    ink(doc, C.muted)
    doc.text(fitText(doc, card.label, cardW - 10), x + 6, y + 7)
    font(doc, 15, 'bold')
    ink(doc, card.signed && (card.v ?? 0) < 0 ? C.negative : C.ink)
    doc.text(card.value, x + 6, y + 15.5)
    font(doc, 7.5, 'normal')
    ink(doc, C.muted)
    doc.text(fitText(doc, card.sub, cardW - 10), x + 6, y + 21.5)
  })
  y += cardH + 9

  // Chart (native): income columns up, expense columns down, result line, dashed previous year.
  font(doc, 10, 'bold')
  ink(doc, C.ink)
  doc.text(L.chartTitle || 'Monthly development', MARGIN, y)
  y += 3
  const chartTop = y + 3
  const chartBottom = FOOTER_Y - 18
  const axisW = 26
  const plotX = MARGIN + axisW
  const plotW = CONTENT_W - axisW
  const plotH = chartBottom - chartTop
  const maxAbs = Math.max(1, ...p.chart.flatMap(r => [r.income, r.expense, Math.abs(r.net ?? 0), Math.abs(r.prevNet ?? 0)]))
  // "nice" axis step
  const rawStep = maxAbs / 4
  const mag = Math.pow(10, Math.floor(Math.log10(rawStep)))
  const step = [1, 2, 2.5, 5, 10].map(m => m * mag).find(s => s >= rawStep) || rawStep
  const axisMax = Math.ceil(maxAbs / step) * step
  const hasNegative = p.chart.some(r => r.expense > 0 || (r.net ?? 0) < 0 || (r.prevNet ?? 0) < 0)
  const axisMin = hasNegative ? -axisMax : 0
  const yOf = (v: number) => chartTop + (axisMax - v) / (axisMax - axisMin) * plotH
  const zeroY = yOf(0)

  stroke(doc, C.grid)
  doc.setLineWidth(0.2)
  font(doc, 7, 'normal')
  ink(doc, C.muted)
  const compact = (v: number) => new Intl.NumberFormat(p.locale, { maximumFractionDigits: 0 }).format(v)
  for (let v = axisMin; v <= axisMax + 1e-9; v += step) {
    const gy = yOf(v)
    doc.line(plotX, gy, plotX + plotW, gy)
    doc.text(compact(v), plotX - 2, gy + 1, { align: 'right' })
  }
  stroke(doc, C.text)
  doc.setLineWidth(0.35)
  doc.line(plotX, zeroY, plotX + plotW, zeroY)

  const slot = plotW / 12
  const barW = slot * 0.56
  p.chart.forEach((r, i) => {
    const cx = plotX + slot * i + slot / 2
    if (r.income > 0) {
      fill(doc, C.income)
      doc.roundedRect(cx - barW / 2, yOf(r.income), barW, Math.max(0.3, zeroY - yOf(r.income)), 0.6, 0.6, 'F')
    }
    if (r.expense > 0) {
      fill(doc, C.expense)
      doc.roundedRect(cx - barW / 2, zeroY, barW, Math.max(0.3, yOf(-r.expense) - zeroY), 0.6, 0.6, 'F')
    }
    font(doc, 7.5, 'normal')
    ink(doc, C.text)
    doc.text(p.monthShort[i] || '', cx, chartBottom + 4.5, { align: 'center' })
  })
  const polyline = (field: 'net' | 'prevNet', color: RGB, dashed: boolean) => {
    stroke(doc, color)
    doc.setLineWidth(0.6)
    if (dashed) doc.setLineDashPattern([1.6, 1.2], 0)
    let prev: { x: number; y: number } | null = null
    p.chart.forEach((r, i) => {
      const v = r[field]
      if (v === null || v === undefined) { prev = null; return }
      const pt = { x: plotX + slot * i + slot / 2, y: yOf(v) }
      if (prev) doc.line(prev.x, prev.y, pt.x, pt.y)
      prev = pt
    })
    if (dashed) doc.setLineDashPattern([], 0)
    if (!dashed) {
      p.chart.forEach((r, i) => {
        const v = r[field]
        if (v === null || v === undefined) return
        const x = plotX + slot * i + slot / 2
        fill(doc, color)
        stroke(doc, C.white)
        doc.setLineWidth(0.4)
        doc.circle(x, yOf(v), 1.1, 'FD')
      })
    }
  }
  const showPrev = p.chart.some(r => r.prevNet !== null && r.prevNet !== undefined)
  if (showPrev) polyline('prevNet', C.muted, true)
  polyline('net', C.ink, false)

  // legend
  let lx = plotX
  const ly = chartBottom + 10
  const legend = (label: string, color: RGB, kind: 'box' | 'line' | 'dash') => {
    if (kind === 'box') { fill(doc, color); doc.rect(lx, ly - 2.2, 3.2, 3.2, 'F') }
    else {
      stroke(doc, color); doc.setLineWidth(0.6)
      if (kind === 'dash') doc.setLineDashPattern([1.2, 1], 0)
      doc.line(lx, ly - 0.6, lx + 5, ly - 0.6)
      if (kind === 'dash') doc.setLineDashPattern([], 0)
    }
    font(doc, 7.5, 'normal')
    ink(doc, C.text)
    doc.text(label, lx + 6.5, ly)
    lx += doc.getTextWidth(label) + 14
  }
  legend(L.income || 'Income', C.income, 'box')
  legend(L.expense || 'Expenses', C.expense, 'box')
  legend(L.result || 'Result', C.ink, 'line')
  if (showPrev) legend(`${L.result || 'Result'} ${p.year - 1}`, C.muted, 'dash')

  // ---------------------------------------------------------------------------
  // Page 2+ — report table

  const isEuer = p.variant === 'euer'
  const lineColW = isEuer ? 9 : 0
  const totalColW = 24
  const monthColW = 16.5
  const labelColW = CONTENT_W - lineColW - totalColW - 12 * monthColW
  const rowH = 5
  const colX = (i: number) => MARGIN + lineColW + labelColW + i * monthColW   // left edge of month i (0..11)
  const totalX = MARGIN + lineColW + labelColW + 12 * monthColW

  const tableHead = () => {
    fill(doc, C.band)
    doc.rect(MARGIN, y, CONTENT_W, rowH + 1, 'F')
    font(doc, 7.5, 'bold')
    ink(doc, C.text)
    const by = y + rowH - 1
    if (isEuer) doc.text(L.line || 'Line', MARGIN + 1.5, by)
    doc.text(L.position || 'Position', MARGIN + lineColW + 1.5, by)
    p.monthShort.forEach((m, i) => {
      const future = p.futureFrom !== null && i + 1 >= p.futureFrom
      ink(doc, future ? C.muted : C.text)
      doc.text(m, colX(i) + monthColW - 1.2, by, { align: 'right' })
    })
    ink(doc, C.text)
    doc.text(`${L.yearTotal || 'Year'} ${p.year}`, totalX + totalColW - 1.2, by, { align: 'right' })
    y += rowH + 1
  }

  const startTablePage = () => {
    doc.addPage()
    header(`${L.reportTable || 'Report'} · ${p.scope}`)
    y = HEADER_H + 9
    tableHead()
  }
  startTablePage()

  const cellText = (row: BankCashPdfRow, i: number) => {
    const v = row.values?.[i] ?? 0
    const future = p.futureFrom !== null && i + 1 >= p.futureFrom
    if (!v && (future || !p.monthHasData[i])) return ''
    return money(v, !row.signed)
  }

  p.rows.forEach((row, idx) => {
    // Keep the closing block (result + the rows after it) together: break early
    // instead of leaving a lone row on the next page.
    const tail = p.rows.length - idx
    const needed = tail <= 4 ? tail * rowH : rowH
    if (y + needed > FOOTER_Y - 8) startTablePage()
    const base = y + rowH - 1.4
    if (row.kind === 'section') {
      y += 1.2
      fill(doc, C.resultSoft)
      doc.rect(MARGIN, y, CONTENT_W, rowH, 'F')
      font(doc, 8, 'bold')
      ink(doc, C.accent)
      doc.text(fitText(doc, row.label, CONTENT_W - 4), MARGIN + 1.5, y + rowH - 1.4)
      y += rowH
      return
    }
    const strong = row.kind === 'sum' || row.kind === 'result'
    if (row.kind === 'result') {
      fill(doc, C.band)
      doc.rect(MARGIN, y, CONTENT_W, rowH, 'F')
    }
    if (strong) {
      stroke(doc, C.text)
      doc.setLineWidth(0.3)
      doc.line(MARGIN, y, PAGE_W - MARGIN, y)
    } else {
      stroke(doc, C.grid)
      doc.setLineWidth(0.15)
      doc.line(MARGIN, y + rowH, PAGE_W - MARGIN, y + rowH)
    }
    const style: any = strong ? 'bold' : row.italic ? 'italic' : 'normal'
    font(doc, 7.5, style)
    ink(doc, row.muted ? C.muted : C.text)
    if (isEuer) {
      font(doc, 7, 'normal')
      ink(doc, C.muted)
      doc.text(row.lineNo || '', MARGIN + 1.5, base)
      font(doc, 7.5, style)
      ink(doc, row.muted ? C.muted : C.text)
    }
    const indent = row.kind === 'sub' ? 4 : 1.5
    const labelMaxW = labelColW - indent - 1
    // "Name · n" when it fits, otherwise the (truncated) name alone.
    const withCount = row.count ? `${row.label} · ${row.count}` : row.label
    const label = doc.getTextWidth(withCount) <= labelMaxW ? withCount : fitText(doc, row.label, labelMaxW)
    doc.text(label, MARGIN + lineColW + indent, base)
    font(doc, 7, strong ? 'bold' : 'normal')
    for (let i = 0; i < 12; i++) {
      const v = row.values?.[i] ?? 0
      ink(doc, row.signed && v < 0 ? C.negative : row.muted ? C.muted : C.text)
      doc.text(cellText(row, i), colX(i) + monthColW - 1.2, base, { align: 'right' })
    }
    font(doc, 7.2, 'bold')
    ink(doc, row.signed && (row.total ?? 0) < 0 ? C.negative : row.muted ? C.muted : C.ink)
    doc.text(money(row.total ?? 0), totalX + totalColW - 1.2, base, { align: 'right' })
    y += rowH
  })
  stroke(doc, C.text)
  doc.setLineWidth(0.3)
  doc.line(MARGIN, y, PAGE_W - MARGIN, y)

  const notes = [L.disclaimer || '']
  if (p.transfers.count) {
    notes.push(p.transfers.included
      ? `${L.transfersIncluded || 'Internal transfers between own accounts included'}: ${p.transfers.count} · ${money(p.transfers.amount)}`
      : `${L.transfersExcluded || 'Internal transfers between own accounts excluded'}: ${p.transfers.count} · ${money(p.transfers.amount)}`)
  }
  if (p.truncated) notes.push(L.truncated || '')
  // Notes go under the table when they fit, otherwise under the counterpart
  // tables — never alone on an extra page.
  const drawNotes = (yStart: number): number => {
    let yy = yStart
    font(doc, 7, 'italic')
    ink(doc, C.muted)
    for (const note of notes.filter(Boolean)) {
      const lines: string[] = doc.splitTextToSize(note, CONTENT_W)
      doc.text(lines, MARGIN, yy)
      yy += lines.length * 3.6 + 1
    }
    return yy
  }
  const notesHeight = (): number => {
    font(doc, 7, 'italic')
    return notes.filter(Boolean).reduce((h, note) => h + (doc.splitTextToSize(note, CONTENT_W) as string[]).length * 3.6 + 1, 0)
  }
  let notesPending = true
  if (y + 5 + notesHeight() <= FOOTER_Y - 6) {
    drawNotes(y + 5)
    notesPending = false
  }

  // ---------------------------------------------------------------------------
  // Page 3 — counterparts

  doc.addPage()
  header(L.counterparts || 'Counterparts')
  y = HEADER_H + 10

  const colGap = 10
  const halfW = (CONTENT_W - colGap) / 2
  const cpTable = (x: number, title: string, list: { top: BankCashPdfCounterpart[]; other: BankCashPdfCounterpart | null }, total: number, sumLabel: string, color: RGB, soft: RGB) => {
    let yy = y
    font(doc, 10, 'bold')
    ink(doc, C.ink)
    doc.text(title, x, yy)
    yy += 4
    const nameW = halfW * 0.44
    const countW = 12
    const amountW = 28
    const shareW = 14
    const barW = halfW - nameW - countW - amountW - shareW - 4
    const cx = { name: x + 1.5, count: x + nameW + countW, amount: x + nameW + countW + amountW, share: x + nameW + countW + amountW + shareW, bar: x + nameW + countW + amountW + shareW + 2 }
    const h = 6
    fill(doc, C.band)
    doc.rect(x, yy, halfW, h, 'F')
    font(doc, 7.5, 'bold')
    ink(doc, C.text)
    doc.text(L.counterpart || 'Counterpart', cx.name, yy + 4.2)
    doc.text(L.count || 'Count', cx.count, yy + 4.2, { align: 'right' })
    doc.text(L.amount || 'Amount', cx.amount, yy + 4.2, { align: 'right' })
    doc.text(L.share || 'Share', cx.share, yy + 4.2, { align: 'right' })
    yy += h
    const maxTotal = Math.max(1, ...list.top.map(r => r.total), list.other?.total || 0)
    const rows = [...list.top.map(r => ({ ...r, muted: false })), ...(list.other ? [{ ...list.other, muted: true }] : [])]
    for (const r of rows) {
      stroke(doc, C.grid)
      doc.setLineWidth(0.15)
      doc.line(x, yy + h, x + halfW, yy + h)
      font(doc, 7.5, r.muted ? 'italic' : 'normal')
      ink(doc, r.muted ? C.muted : C.text)
      doc.text(fitText(doc, r.name, nameW - 3), cx.name, yy + 4.2)
      doc.text(String(r.count), cx.count, yy + 4.2, { align: 'right' })
      font(doc, 7.5, r.muted ? 'italic' : 'bold')
      doc.text(money(r.total), cx.amount, yy + 4.2, { align: 'right' })
      font(doc, 7.5, 'normal')
      doc.text(percent(r.total, total), cx.share, yy + 4.2, { align: 'right' })
      fill(doc, soft)
      doc.rect(cx.bar, yy + 1.6, barW, h - 3.2, 'F')
      fill(doc, r.muted ? C.muted : color)
      doc.rect(cx.bar, yy + 1.6, Math.max(0.4, barW * r.total / maxTotal), h - 3.2, 'F')
      yy += h
    }
    stroke(doc, C.text)
    doc.setLineWidth(0.3)
    doc.line(x, yy, x + halfW, yy)
    font(doc, 8, 'bold')
    ink(doc, C.ink)
    doc.text(sumLabel, cx.name, yy + 4.4)
    doc.text(money(total), cx.amount, yy + 4.4, { align: 'right' })
    return yy + h
  }
  const y1 = cpTable(MARGIN, L.topPayers || 'Top payers (income)', p.payers, p.kpis.income, L.sumIncome || 'Total revenue', C.income, C.incomeSoft)
  const y2 = cpTable(MARGIN + halfW + colGap, L.topPayees || 'Top payees (expenses)', p.payees, p.kpis.expense, L.sumExpense || 'Total expenses', C.expense, C.expenseSoft)
  if (notesPending) drawNotes(Math.max(y1, y2) + 8)

  footers()
  return doc
}
