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 { jsPDF } from 'jspdf'

import fetchHelper from '../../utils/fetchHelper'
import getTokenHelper from '../../utils/getTokenHelper'

// let notoSansBase64: string | null = null
// async function getNotoSansBase64() {
//   if (!notoSansBase64) {
//     const storage = useStorage('assets:server')
//     const fontBuffer = await storage.getItemRaw<Buffer>('fonts/NotoSans-Regular.ttf')
//     notoSansBase64 = Buffer.from(fontBuffer!).toString('base64')
//   }
//   return notoSansBase64
// }

const labelByPrinter = (doc, no, entry, orgNames = {}, customSettings = null) => {
  const s = customSettings
  if(entry.labelPrinterId === 'b') {
    doc.addPage()
    doc.setPage(no)
    doc.setFontSize(s?.productFontSize ?? 18)
    doc.text(String(entry.product.replace("FOREVER ", "")), s?.productX ?? 0, s?.productY ?? 6)
    doc.setFontSize(s?.skuFontSize ?? 15)
    doc.text(String( 'SKU:'+ entry.productSKU+ ' - '+ entry.organizationId?.toString().slice(-2)), s?.skuX ?? 0, s?.skuY ?? 13)
    doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 1, s?.barcodeY ?? 16, s?.barcodeW ?? 74, s?.barcodeH ?? 32)
  } else if(entry.labelPrinterId === 'c') {
    doc.addPage()
    doc.setPage(no)
    doc.setFontSize(s?.productFontSize ?? 12)
    const productText = String(entry.product.replace("FOREVER ", ""))
    const splitProduct = doc.splitTextToSize(productText, s?.productW ?? 70)
    doc.text(splitProduct, s?.productX ?? 0, s?.productY ?? 5)
    const productLines = Math.min(splitProduct.length, 3)
    const tableStart = (s?.productY ?? 5) + (productLines * 5)
    doc.setFontSize(s?.tableFontSize ?? 9)
      doc.rect(1, tableStart, 71, 4)
      doc.text(String('SKU: ' + entry.productSKU), 2, tableStart + 3)
      doc.rect(1, tableStart + 4, 32, 4)
      doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStart + 7)
      doc.rect(33, tableStart + 4, 39, 4)
      doc.text(String('EAN: ' + entry.productUPC), 35, tableStart + 7)
      doc.rect(1, tableStart + 8, 32, 4)
      doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStart + 11)
      doc.rect(33, tableStart + 8, 39, 4)
      doc.text(String(new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStart + 11)
      doc.setFontSize(12)
    doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, tableStart + 13, s?.barcodeW ?? 70, s?.barcodeH ?? 20)
  } else if(entry.labelPrinterId === 'd') {
    doc.addPage()
    doc.setPage(no)
    doc.setFontSize(s?.productFontSize ?? 12)
    const productTextD = String(entry.product.replace("FOREVER ", ""))
    const splitProductD = doc.splitTextToSize(productTextD, s?.productW ?? 70)
    doc.text(splitProductD, s?.productX ?? 0, s?.productY ?? 5)
    doc.setFontSize(s?.tableFontSize ?? 9)
    const tableStartD = s?.tableStartY ?? 19
      doc.rect(1, tableStartD, 71, 4)
      doc.text(String('SKU: ' + entry.productSKU), 2, tableStartD + 3)
      doc.rect(1, tableStartD + 4, 32, 4)
      doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStartD + 7)
      doc.rect(33, tableStartD + 4, 39, 4)
      doc.text(String('EAN: ' + entry.productUPC), 35, tableStartD + 7)
      doc.rect(1, tableStartD + 8, 32, 4)
      doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartD + 11)
      doc.rect(33, tableStartD + 8, 39, 4)
      doc.text(String( new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStartD + 11)
      doc.setFontSize(12)
    doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, s?.barcodeY ?? 32, s?.barcodeW ?? 70, s?.barcodeH ?? 20)
  } else if(entry.labelPrinterId === 'e') {
    doc.addPage()
    doc.setPage(no)
    doc.setFontSize(s?.productFontSize ?? 12)
    const productTextE = String(entry.product.replace("FOREVER ", ""))
    const splitProductE = doc.splitTextToSize(productTextE, s?.productW ?? 70)
    doc.text(splitProductE, s?.productX ?? 0, s?.productY ?? 5)
    doc.setFontSize(s?.tableFontSize ?? 9)
    const tableStartE = s?.tableStartY ?? 19
      doc.rect(1, tableStartE, 71, 4)
      doc.text(String('SKU: ' + entry.productSKU), 2, tableStartE + 3)
      doc.rect(1, tableStartE + 4, 32, 4)
      doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStartE + 7)
      doc.rect(33, tableStartE + 4, 39, 4)
      doc.text(String('EAN: ' + entry.productUPC), 35, tableStartE + 7)
      doc.rect(1, tableStartE + 8, 32, 4)
      doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartE + 11)
      doc.rect(33, tableStartE + 8, 39, 4)
      doc.text(String('Erst.:' + new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStartE + 11)
      doc.setFontSize(12)
    doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, s?.barcodeY ?? 32, s?.barcodeW ?? 70, s?.barcodeH ?? 20)
  } else if(entry.labelPrinterId === 'f') {
    let fFormat = [54, 52]
    if (s?.format && /^\d+,\d+$/.test(s.format)) {
      const [w, h] = s.format.split(',').map(Number)
      fFormat = [w, h]
    }
    doc.addPage(fFormat)
    doc.setPage(no)
    doc.setFontSize(s?.productFontSize ?? 12)
    const productTextF = String(entry.product.replace("FOREVER ", ""))
    const splitProductF = doc.splitTextToSize(productTextF, s?.productW ?? 52)
    doc.text(splitProductF, s?.productX ?? 0, s?.productY ?? 6)
    const productLinesF = Math.min(splitProductF.length, 3)
    const tableStartF = (s?.productY ?? 6) + (productLinesF * 5)
    doc.setFontSize(s?.tableFontSize ?? 9)
      doc.rect(1, tableStartF, 51, 4)
      doc.text(String('SKU: ' + entry.productSKU), 2, tableStartF + 3)
      doc.rect(1, tableStartF + 4, 25, 4)
      doc.text(String('Art:' + entry.productValue), 2, tableStartF + 7)
      doc.rect(26, tableStartF + 4, 26, 4)
      doc.text(String('EAN: ' + entry.productUPC), 27, tableStartF + 7)
      doc.rect(1, tableStartF + 8, 25, 4)
      doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartF + 11)
      doc.rect(26, tableStartF + 8, 26, 4)
      doc.text(String('Erst:' + new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 27, tableStartF + 11)
      doc.setFontSize(12)
    doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, tableStartF + 14, s?.barcodeW ?? 50, s?.barcodeH ?? 18)
  } else {
    doc.addPage()
    doc.setPage(no)
    doc.setFontSize(18)
    doc.text(String(entry.product.replace("FOREVER ", "")), 0, 8)
    doc.setFontSize(14)
    doc.text(String( 'SKU: '+ entry.productSKU + ' | VAL: ' + entry.productValue+ ' | ORG: '+ entry.organizationId?.toString().slice(-2)), 0, 17)
    doc.addImage(entry.labelBarcode, 'image/png', 9, 20, 60, 28)
  }
}

const serverPrinting = async (item) => {
  const exec = promisify(child_process.exec)
  const labelPrinters = {
    a: 'labelprinter-1',
    b: 'labelprinter-2',
    c: 'labelprinter-3',
    d: 'labelprinter-4',
    e: 'labelprinter-5',
    f: 'labelprinter-6',
  }
  const labelPrinter = labelPrinters[item.labelEntry] || 'labelprinter-2'

  // Report the TRUE outcome. `lp` exits non-zero (→ exec throws) when the queue
  // is unknown/disabled/not-accepting, or when the file can't be written — so a
  // throw here means the label did NOT print. Previously this error was swallowed
  // and the caller counted "PDF generated" as "printed", hiding every failure.
  const result: any = { ok: false, printer: labelPrinter, stdout: '', stderr: '', error: '' }
  try {
    if(!existsSync(item.filePath)) {
      mkdirSync(item.filePath, { recursive: true })
    }
    await writeFile(`${item.filePath}/${item.fileName}`, Buffer.from(item.fileContent, 'base64'))

    const { stdout, stderr } = await exec(`lp -d ${labelPrinter} -o fit-to-page ${item.filePath}/${item.fileName}`);

    result.stdout = stdout || ''
    result.stderr = stderr || ''
    result.ok = true
  } catch(err: any) {
    result.error = err?.stderr || err?.message || err?.data?.message || 'Error when printing via server side'
    result.stderr = err?.stderr || ''
    result.ok = false
  }
  return result
}

export default defineEventHandler(async (event) => {
  let data: any = {}
  const body = await readBody(event)
  const exec = promisify(child_process.exec)
  const pathName = body.pathName
  const filePath = `/root/storage/${pathName}`
  const fileName = body.fileName
  const labelEntries = body.labelEntries
  const customSettings = body.customSettings || null
  // When true, generate the PDFs server-side and return them, but do NOT
  // send them to the physical label printer. Used by the "Download Labels"
  // button on receipt edit so users can grab the file without reprinting.
  const downloadOnly = body.downloadOnly === true

  data['path'] = filePath
  data['name'] = fileName
  data['contents'] = []
  data['printResults'] = []

  // Fetch org company names once for the entire print session
  const orgNames: Record<string, string> = {}
  try {
    const orgIds = [...new Set(labelEntries.flatMap(([, vals]) => vals.flat().map((e: any) => e.organizationId)).filter(Boolean))]
    if (orgIds.length > 0) {
      const token = await getTokenHelper(event)
      const orgFilter = orgIds.map(id => `AD_Org_ID eq ${id}`).join(' or ')
      const orgRes: any = await fetchHelper(event, `models/ad_org?$filter=${orgFilter}&$select=AD_Org_ID,companyname,Name`, 'GET', token, null)
      for (const org of orgRes?.records || []) {
        orgNames[org.id] = org.companyname || org.Name || ''
      }
    }
  } catch (e) {
    // fallback: orgNames stays empty, label will use organizationId
  }

  for(const [labelEntry, labelValues] of labelEntries) {
    let pageFormat: any = 'a8'
    if (customSettings?.format) {
      const formatStr = customSettings.format
      if (/^\d+,\d+$/.test(formatStr)) {
        const [w, h] = formatStr.split(',').map(Number)
        pageFormat = [w, h]
      } else {
        pageFormat = formatStr
      }
    }

    const doc = new jsPDF({
      orientation: 'l',
      unit: 'mm',
      format: pageFormat,
      putOnlyUsedFonts: true,
      compress: true
    })

    // doc.addFileToVFS('NotoSans-Regular.ttf', await getNotoSansBase64())
    // doc.addFont('NotoSans-Regular.ttf', 'NotoSans', 'normal')
    // doc.setFont('NotoSans')

    doc.addPage()

    let no = 2;
    for(let entry of labelValues.flat()) {
      for(let i = 0; i < Number(entry.qtyEntered || 0); i++) {
        labelByPrinter(doc, no, entry, orgNames, customSettings)

        no++
      }
    }

    doc.deletePage(1)
    doc.deletePage(Number(no) - 1)

    const fileContent = doc.output('dataurlstring')?.replace('data:application/pdf;filename=generated.pdf;base64,', '')
    data['contents'].push({
      label: labelEntry,
      content: fileContent
    })
    if (!downloadOnly) {
      const resPrint = await serverPrinting({
        filePath,
        fileName: fileName.replace('-LABELS-', `-LABELPRINTER-${labelEntry}-`),
        fileContent,
        labelEntry
      })
      if(resPrint) {
        data['print_result'] = resPrint            // kept for backward-compat (last group)
        data['printResults'].push({ labelEntry, ...resPrint })
      }
    }
  }

  // Honest overall verdict: did EVERY printer group actually reach the printer?
  // (Only meaningful when we actually printed — download-only never prints.)
  if (!downloadOnly) {
    data['printOk'] = data['printResults'].length > 0 && data['printResults'].every((r: any) => r.ok)
  }

  return data
})