import { promisify } from 'node:util'
import child_process from 'node:child_process'
import { existsSync, mkdirSync } from 'node:fs'
import { writeFile } from 'node:fs/promises'
import { renderPdfmake } from '../../../utils/offers/agbPdf'

/**
 * Mobile reconditioning — A4 "Umlagerungsbericht" (movement report).
 *
 * Renders (pdfmake, server-side so the Capacitor bundle needs no PDF library) a one-page
 * A4 sheet that tells the warehouse where each reconditioned article has to go and how
 * many, plus the articles that were disposed of instead, and sends it to a CUPS paper
 * queue via `lp` — same mechanics as /api/print/picklist (whitelisted queue name,
 * `-o sides=one-sided`). Printing is fail-soft for the caller: the movement is already
 * booked, so a print failure only produces a warning toast on the phone.
 *
 * Body: {
 *   printer?: string,          // CUPS queue (CUST_Printer.cupsName); '' → CUPS default
 *   returnPdf?: boolean,       // also return the PDF as base64 (preview / dev without CUPS)
 *   report: {
 *     returnDocumentNo, rmaDocumentNo, partnerName, orgName, userName,
 *     movementDocumentNo?, inventoryDocumentNo?,
 *     moveLines: [{ value, name, qty, fromCode, toCode }],
 *     disposeLines: [{ value, name, qty, fromCode }]
 *   }
 * }
 */
const SAFE_PRINTER = /^[A-Za-z0-9_.-]+$/
const STORAGE_DIR = '/root/storage/reconditioning'

const s = (v: any) => (v === undefined || v === null) ? '' : String(v)
const fmtDateTime = (d: Date) => d.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })

const buildDocDefinition = (r: any) => {
  const moveLines: any[] = Array.isArray(r?.moveLines) ? r.moveLines : []
  const disposeLines: any[] = Array.isArray(r?.disposeLines) ? r.disposeLines : []
  const totalMove = moveLines.reduce((sum, l) => sum + (Number(l.qty) || 0), 0)
  const totalDispose = disposeLines.reduce((sum, l) => sum + (Number(l.qty) || 0), 0)

  // Group by target locator so one locator = one block the picker can work through.
  const byTarget = new Map<string, any[]>()
  for (const l of moveLines) {
    const key = s(l.toCode) || '–'
    if (!byTarget.has(key)) byTarget.set(key, [])
    byTarget.get(key)!.push(l)
  }
  const targets = [...byTarget.keys()].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))

  const headCell = (text: string, alignment: string = 'left') => ({ text, style: 'th', alignment })
  const cell = (text: string, alignment: string = 'left', extra: any = {}) => ({ text, alignment, ...extra })

  const content: any[] = [
    { text: 'Reconditioning – Umlagerungsbericht', style: 'title' },
    {
      columns: [
        {
          width: '*',
          stack: [
            { text: [{ text: 'Retoure: ', bold: true }, s(r?.returnDocumentNo) || '–'] },
            { text: [{ text: 'RMA: ', bold: true }, s(r?.rmaDocumentNo) || '–'] },
            { text: [{ text: 'Kunde: ', bold: true }, s(r?.partnerName) || '–'] },
            { text: [{ text: 'Organisation: ', bold: true }, s(r?.orgName) || '–'] }
          ]
        },
        {
          width: '*',
          stack: [
            { text: [{ text: 'Datum: ', bold: true }, fmtDateTime(new Date())] },
            { text: [{ text: 'Bearbeiter: ', bold: true }, s(r?.userName) || '–'] },
            { text: [{ text: 'Umlagerung: ', bold: true }, s(r?.movementDocumentNo) || '–'] },
            ...(disposeLines.length ? [{ text: [{ text: 'Inventur (Entsorgung): ', bold: true }, s(r?.inventoryDocumentNo) || '–'] }] : [])
          ]
        }
      ],
      margin: [0, 6, 0, 14]
    }
  ]

  if (moveLines.length) {
    content.push({ text: `Einlagern – ${totalMove} Stk in ${targets.length} Lagerplatz${targets.length === 1 ? '' : 'e'}`, style: 'h2' })
    for (const target of targets) {
      const lines = byTarget.get(target)!.slice().sort((a, b) => s(a.value).localeCompare(s(b.value), undefined, { numeric: true }))
      const sub = lines.reduce((sum, l) => sum + (Number(l.qty) || 0), 0)
      content.push({
        table: {
          headerRows: 1,
          widths: [22, 80, '*', 72, 40, 62],
          body: [
            [
              { text: '', style: 'th' },
              { text: 'Ziel: ' + target, style: 'thTarget', colSpan: 5 }, {}, {}, {}, {}
            ],
            [headCell('OK', 'center'), headCell('Artikel-Nr.'), headCell('Bezeichnung'), headCell('Von Lagerplatz'), headCell('Menge', 'right'), headCell('Ziel', 'left')],
            ...lines.map((l) => [
              { canvas: [{ type: 'rect', x: 4, y: 1, w: 10, h: 10, lineWidth: 0.8 }] },
              cell(s(l.value) || '–', 'left', { style: 'mono' }),
              cell(s(l.name)),
              cell(s(l.fromCode) || '–', 'left', { style: 'mono' }),
              cell(String(Number(l.qty) || 0), 'right', { bold: true, fontSize: 12 }),
              cell(target, 'left', { style: 'mono', bold: true })
            ]),
            [
              { text: '', colSpan: 4 }, {}, {}, {},
              cell(String(sub), 'right', { bold: true }),
              { text: 'Stk', italics: true }
            ]
          ]
        },
        layout: 'lightHorizontalLines',
        margin: [0, 0, 0, 12]
      })
    }
  }

  if (disposeLines.length) {
    const lines = disposeLines.slice().sort((a, b) => s(a.value).localeCompare(s(b.value), undefined, { numeric: true }))
    content.push({ text: `Entsorgen – ${totalDispose} Stk (nicht aufbereitbar, Bestand ausgebucht)`, style: 'h2', color: '#b45309' })
    content.push({
      table: {
        headerRows: 1,
        widths: [22, 80, '*', 72, 40, 62],
        body: [
          [headCell('OK', 'center'), headCell('Artikel-Nr.'), headCell('Bezeichnung'), headCell('Von Lagerplatz'), headCell('Menge', 'right'), headCell('Aktion')],
          ...lines.map((l) => [
            { canvas: [{ type: 'rect', x: 4, y: 1, w: 10, h: 10, lineWidth: 0.8 }] },
            cell(s(l.value) || '–', 'left', { style: 'mono' }),
            cell(s(l.name)),
            cell(s(l.fromCode) || '–', 'left', { style: 'mono' }),
            cell(String(Number(l.qty) || 0), 'right', { bold: true, fontSize: 12 }),
            cell('ENTSORGEN', 'left', { bold: true, color: '#b45309' })
          ])
        ]
      },
      layout: 'lightHorizontalLines',
      margin: [0, 0, 0, 12]
    })
  }

  content.push({
    columns: [
      { width: '*', stack: [{ canvas: [{ type: 'line', x1: 0, y1: 0, x2: 200, y2: 0, lineWidth: 0.7 }] }, { text: 'Umgelagert von / Datum', fontSize: 8, color: '#666', margin: [0, 2, 0, 0] }] },
      { width: '*', stack: [{ canvas: [{ type: 'line', x1: 0, y1: 0, x2: 200, y2: 0, lineWidth: 0.7 }] }, { text: 'Geprüft von / Datum', fontSize: 8, color: '#666', margin: [0, 2, 0, 0] }] }
    ],
    margin: [0, 30, 0, 0]
  })

  return {
    pageSize: 'A4',
    pageMargins: [36, 36, 36, 40],
    defaultStyle: { fontSize: 10 },
    styles: {
      title: { fontSize: 18, bold: true, margin: [0, 0, 0, 4] },
      h2: { fontSize: 13, bold: true, margin: [0, 8, 0, 6] },
      th: { bold: true, fillColor: '#f1f5f9', fontSize: 9 },
      thTarget: { bold: true, fontSize: 12, fillColor: '#dbeafe' },
      mono: { fontSize: 10 }
    },
    footer: (currentPage: number, pageCount: number) => ({
      columns: [
        { text: `Reconditioning · Retoure ${s(r?.returnDocumentNo)}${s(r?.rmaDocumentNo) ? ' · RMA ' + s(r?.rmaDocumentNo) : ''}`, fontSize: 8, color: '#666' },
        { text: `Seite ${currentPage} / ${pageCount}`, alignment: 'right', fontSize: 8, color: '#666' }
      ],
      margin: [36, 10, 36, 0]
    }),
    content
  }
}

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  const report = body?.report || {}
  const returnPdf = body?.returnPdf === true
  const printer = SAFE_PRINTER.test(body?.printer || '') ? String(body.printer) : ''

  let buffer: Buffer
  try {
    buffer = await renderPdfmake(buildDocDefinition(report))
  } catch (err: any) {
    console.error('[reconditioning/print-report] PDF render failed:', err)
    setResponseStatus(event, 500)
    return { status: 500, message: 'PDF konnte nicht erzeugt werden: ' + (err?.message || err) }
  }

  const safeDoc = s(report?.returnDocumentNo).replace(/[^A-Za-z0-9_-]/g, '') || 'retoure'
  const fileName = `Reconditioning-${safeDoc}-${Date.now()}.pdf`
  const result: any = { status: 200, fileName, printer: printer || 'default', printed: false }
  if (returnPdf) result.pdfBase64 = buffer.toString('base64')

  if (body?.print === false) return result

  try {
    if (!existsSync(STORAGE_DIR)) mkdirSync(STORAGE_DIR, { recursive: true })
    const filePath = `${STORAGE_DIR}/${fileName}`
    await writeFile(filePath, buffer)
    const exec = promisify(child_process.exec)
    const { stdout, stderr } = await exec(`lp ${printer ? '-d ' + printer + ' ' : ''}-o sides=one-sided -o media=A4 ${filePath}`)
    result.printed = !stderr
    result.stdout = stdout
    result.stderr = stderr
    if (stderr) {
      result.status = 500
      result.message = 'Druck fehlgeschlagen: ' + stderr
      setResponseStatus(event, 500)
    }
  } catch (err: any) {
    console.error('[reconditioning/print-report] print failed:', err)
    result.status = 500
    result.message = 'Druck fehlgeschlagen: ' + (err?.message || err)
    setResponseStatus(event, 500)
  }
  return result
})
