import { getStroke } from 'perfect-freehand'
import { DEFAULT_STROKE_OPTIONS, DEFAULT_SIZE, DEFAULT_INK, DEFAULT_TEXT_SIZE } from './canvas'
import { type NoteDocument, type NoteBackground, pageDimensions } from './document'

/**
 * Multi-page A4 PDF export for note documents (KAR-662).
 *
 * Renders strokes as jspdf **vector** polygons (perfect-freehand outline →
 * filled path) and the grid/lines background as jspdf lines — no SVG→canvas
 * rasterisation. This mirrors the agenda export (lib/agenda/export-pdf.ts),
 * runs in Node + browser, and avoids the fragile `<img>`-rasterise path.
 */

const RULE_HEX = '#C1C5CB'

function hexToRgb(hex: string): [number, number, number] {
  const h = hex.replace('#', '')
  const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h
  const n = parseInt(full, 16)
  return [(n >> 16) & 255, (n >> 8) & 255, n & 255]
}

type JsPdfDoc = import('jspdf').jsPDF

function drawBackground(
  pdf: JsPdfDoc,
  background: NoteBackground,
  gridMm: number,
  widthMm: number,
  heightMm: number,
): void {
  if (background === 'blank') return
  const [r, g, b] = hexToRgb(RULE_HEX)
  pdf.setDrawColor(r, g, b)
  pdf.setLineWidth(0.1)
  // Horizontal rules for both grid and lines.
  for (let y = gridMm; y < heightMm; y += gridMm) pdf.line(0, y, widthMm, y)
  // Vertical rules only for the grid.
  if (background === 'grid') {
    for (let x = gridMm; x < widthMm; x += gridMm) pdf.line(x, 0, x, heightMm)
  }
}

/** Build a multi-page A4 PDF (vector) from a note document. Node + browser. */
export async function buildNotePdf(document: NoteDocument): Promise<Blob> {
  const { jsPDF } = await import('jspdf')
  const orientation = document.orientation === 'landscape' ? 'l' : 'p'
  const pdf = new jsPDF({ orientation, unit: 'mm', format: 'a4' })
  const widthMm = document.orientation === 'landscape' ? 297 : 210
  const heightMm = document.orientation === 'landscape' ? 210 : 297
  const px = pageDimensions(document.orientation)
  const sx = widthMm / px.width
  const sy = heightMm / px.height

  document.pages.forEach((page, index) => {
    if (index > 0) pdf.addPage('a4', orientation)
    drawBackground(pdf, document.background, document.gridMm, widthMm, heightMm)

    for (const stroke of page.strokes) {
      if (stroke.points.length === 0) continue
      const outline = getStroke(stroke.points, {
        ...DEFAULT_STROKE_OPTIONS,
        size: stroke.size ?? DEFAULT_SIZE,
      }) as number[][]
      if (outline.length < 2) continue

      const [r, g, b] = hexToRgb(stroke.color ?? DEFAULT_INK)
      pdf.setFillColor(r, g, b)
      const startX = outline[0][0] * sx
      const startY = outline[0][1] * sy
      const segments = outline
        .slice(1)
        .map((p, i) => [(p[0] - outline[i][0]) * sx, (p[1] - outline[i][1]) * sy])
      pdf.lines(segments, startX, startY, [1, 1], 'F', true)
    }

    for (const t of page.texts ?? []) {
      if (t.text.trim().length === 0) continue
      const [r, g, b] = hexToRgb(t.color ?? DEFAULT_INK)
      pdf.setTextColor(r, g, b)
      // A4-px font size → mm (× sy) → pt (× 72/25.4).
      pdf.setFontSize((t.size ?? DEFAULT_TEXT_SIZE) * sy * (72 / 25.4))
      pdf.text(t.text, t.x * sx, t.y * sy, { baseline: 'top' })
    }
  })

  return pdf.output('blob')
}

/* tdd-guard:skip — browser-only download trigger. */
export function downloadBlob(blob: Blob, filename: string): void {
  const url = URL.createObjectURL(blob)
  const a = window.document.createElement('a')
  a.href = url
  a.download = filename
  window.document.body.appendChild(a)
  a.click()
  a.remove()
  URL.revokeObjectURL(url)
}

/* tdd-guard:skip — browser-only Blob→base64 for the server action. */
export async function blobToBase64(blob: Blob): Promise<string> {
  const buffer = await blob.arrayBuffer()
  const bytes = new Uint8Array(buffer)
  let binary = ''
  for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i])
  return btoa(binary)
}
