// Generates the same "Picklist" PDF that /generate-shipments produces, but
// from an arbitrary set of m_inout document numbers (e.g. the currently-open
// "Zu kommissionieren" shipments on the dashboard).
//
// Mirrors the data fetch + aggregation + sort + pdfmake layout in
// pages/generate-shipments.vue so both code paths produce identical output.

interface PicklistOptions {
  docNos: string[]
  sortBy?: 'locator' | 'value' | 'sku' | 'mpn' | 'upc' | 'name' | 'qty' | ''
  userName?: string
  title?: string
}

const loadPdfMake = async () => {
  const pdfMakeModule: any = await import('pdfmake/build/pdfmake.js')
  const pdfFontsModule: any = await import('pdfmake/build/vfs_fonts.js')
  const pdfMake = pdfMakeModule.default || pdfMakeModule

  let vfs: any = null
  if (pdfFontsModule.pdfMake?.vfs) vfs = pdfFontsModule.pdfMake.vfs
  else if (pdfFontsModule.default?.pdfMake?.vfs) vfs = pdfFontsModule.default.pdfMake.vfs
  else if (pdfFontsModule.default?.vfs) vfs = pdfFontsModule.default.vfs
  else if (pdfFontsModule.default) {
    const keys = Object.keys(pdfFontsModule.default)
    if (keys.some(k => k.endsWith('.ttf'))) vfs = pdfFontsModule.default
  }
  pdfMake.vfs = vfs
  return pdfMake
}

// Shared comparator: organization first, then the chosen field. Used both to sort
// the aggregated picklist rows AND to derive the shipment print order, so the
// shipments print in exactly the same order the picklist is sorted in.
const lineComparator = (sortBy: string) => (a: any, b: any) => {
  const orgCompare = (a.AD_Org_ID?.identifier || '').localeCompare(b.AD_Org_ID?.identifier || '')
  if (orgCompare !== 0) return orgCompare
  if (!sortBy) return 0
  switch (sortBy) {
    case 'value':
      return (a.M_Product_ID?.Value || '').localeCompare(b.M_Product_ID?.Value || '')
    case 'sku':
      return (a.M_Product_ID?.SKU || '').localeCompare(b.M_Product_ID?.SKU || '')
    case 'mpn':
      return (a.M_Product_ID?.mpn || '').localeCompare(b.M_Product_ID?.mpn || '')
    case 'upc':
      return (a.M_Product_ID?.UPC || '').localeCompare(b.M_Product_ID?.UPC || '')
    case 'name':
      return (a.M_Product_ID?.Name || '').localeCompare(b.M_Product_ID?.Name || '')
    case 'qty':
      return Number(b.QtyEntered) - Number(a.QtyEntered)
    case 'locator': {
      const xCompare = (a.M_Locator_ID?.X || '').toString().localeCompare((b.M_Locator_ID?.X || '').toString(), undefined, { numeric: true })
      if (xCompare !== 0) return xCompare
      const yCompare = (a.M_Locator_ID?.Y || '').toString().localeCompare((b.M_Locator_ID?.Y || '').toString(), undefined, { numeric: true })
      if (yCompare !== 0) return yCompare
      return (a.M_Locator_ID?.Z || '').toString().localeCompare((b.M_Locator_ID?.Z || '').toString(), undefined, { numeric: true })
    }
    default:
      return 0
  }
}

const sortPicklistData = (data: any[], sortBy: string) => [...data].sort(lineComparator(sortBy))

export const useGenerateOpenPicklistPdf = () => {
  const generate = async ({ docNos, sortBy = 'locator', userName = 'SUPERUSER', title = 'Picklist' }: PicklistOptions) => {
    if (!docNos?.length) return { ok: false, reason: 'no-docs' as const }

    const aggregated: any[] = []
    const relatedDocNos: string[] = []
    // Flat product lines tagged with their shipment + a docNo→shipment map, used to
    // derive the shipment print order (same comparator as the picklist). Does not
    // affect the picklist PDF itself.
    const orderLines: any[] = []
    const shipmentByDocNo = new Map<string, { id: any, documentNo: string }>()

    for (const docNo of docNos) {
      if (!docNo) continue
      let res: any
      try {
        res = await $fetch('/api/processes/inouts/' + docNo)
      } catch (e) {
        continue
      }
      if (!res?.records?.[0]) continue
      if (!relatedDocNos.includes(docNo)) relatedDocNos.push(docNo)

      const docRes = res.records[0]
      if (!shipmentByDocNo.has(docNo)) shipmentByDocNo.set(docNo, { id: docRes.id, documentNo: docNo })
      const productLines = (docRes.m_inoutline || []).filter((l: any) => l.M_Product_ID && l.M_Locator_ID && !l.C_Charge_ID)

      for (const drl of productLines) {
        orderLines.push({ ...drl, _docNo: docNo })
        const existingIdx = aggregated.findIndex(i =>
          i.AD_Org_ID?.id == drl.AD_Org_ID?.id &&
          i.M_Product_ID?.Value == drl.M_Product_ID?.Value &&
          i.M_Locator_ID?.X == drl.M_Locator_ID?.X &&
          i.M_Locator_ID?.Y == drl.M_Locator_ID?.Y &&
          i.M_Locator_ID?.Z == drl.M_Locator_ID?.Z
        )
        if (existingIdx >= 0) {
          aggregated[existingIdx].QtyEntered = Number(aggregated[existingIdx].QtyEntered) + Number(drl.QtyEntered)
        } else {
          aggregated.push({ ...drl })
        }
      }
    }

    if (!aggregated.length) return { ok: false, reason: 'no-lines' as const }

    const sorted = sortPicklistData(aggregated, sortBy)

    // Shipment print order — same comparator the picklist uses, first occurrence per
    // shipment, so the referenced shipments print in the picklist's order.
    const orderedShipments: { id: any, documentNo: string }[] = []
    const seenDoc = new Set<string>()
    for (const line of [...orderLines].sort(lineComparator(sortBy))) {
      if (seenDoc.has(line._docNo)) continue
      seenDoc.add(line._docNo)
      const sh = shipmentByDocNo.get(line._docNo)
      if (sh) orderedShipments.push(sh)
    }
    // Shipments without pickable product lines still belong in the batch — append them.
    for (const [doc, sh] of shipmentByDocNo) {
      if (!seenDoc.has(doc)) { seenDoc.add(doc); orderedShipments.push(sh) }
    }

    const today = new Date().toLocaleString('de-DE', {
      day: '2-digit', month: '2-digit', year: 'numeric',
      hour: '2-digit', minute: '2-digit', second: '2-digit'
    })

    const pdfMake = await loadPdfMake()

    const tableBody: any[] = [
      [
        { text: 'Org', style: 'tableHeader' },
        { text: 'Loc', style: 'tableHeader' },
        { text: 'Name', style: 'tableHeader' },
        { text: 'Value', style: 'tableHeader' },
        { text: 'SKU', style: 'tableHeader' },
        { text: 'MPN', style: 'tableHeader' },
        { text: 'UPC', style: 'tableHeader' },
        { text: 'Qty', style: 'tableHeader', alignment: 'center' },
      ],
      ...sorted.map((item: any) => {
        return [
          { text: item.AD_Org_ID?.identifier || '-', style: 'tableCell' },
          { text: `${item.M_Locator_ID?.X ?? ''},${item.M_Locator_ID?.Y ?? ''},${item.M_Locator_ID?.Z ?? ''}`, style: 'tableCell' },
          { text: item.M_Product_ID?.Name || '-', style: 'tableCell' },
          { text: item.M_Product_ID?.Value || '-', style: 'tableCell' },
          { text: item.M_Product_ID?.SKU || '-', style: 'tableCell' },
          { text: item.M_Product_ID?.mpn || '-', style: 'tableCell' },
          { text: item.M_Product_ID?.UPC || '-', style: 'tableCell' },
          { text: String(item.QtyEntered ?? ''), style: 'tableCell', alignment: 'center' },
        ]
      }),
    ]

    const content: any[] = [
      { text: title, style: 'title', alignment: 'center' },
      { text: today, style: 'subtitle', alignment: 'center', margin: [0, 2, 0, 8] },
      {
        table: {
          headerRows: 1,
          widths: [40, 48, '*', 66, 66, 66, 66, 26],
          body: tableBody,
          dontBreakRows: true,
        },
        layout: {
          hLineWidth: () => 0.5,
          vLineWidth: () => 0.5,
          hLineColor: () => '#9f9f9f',
          vLineColor: () => '#9f9f9f',
          fillColor: (rowIndex: number) => rowIndex === 0 ? '#f2f2f2' : null,
          paddingLeft: () => 3,
          paddingRight: () => 3,
          paddingTop: () => 2,
          paddingBottom: () => 2,
        },
      },
    ]

    if (relatedDocNos.length > 0) {
      content.push({
        margin: [0, 8, 0, 0],
        table: {
          widths: ['*'],
          body: [[{
            stack: [
              { text: `Related Shipments (${relatedDocNos.length})`, fontSize: 7, bold: true, margin: [0, 0, 0, 3] },
              { text: relatedDocNos.join(', '), fontSize: 6.5, lineHeight: 1.4 },
            ],
            margin: [4, 4, 4, 4],
          }]],
        },
        layout: {
          hLineWidth: () => 0.5,
          vLineWidth: () => 0.5,
          hLineColor: () => '#9f9f9f',
          vLineColor: () => '#9f9f9f',
        },
      })
    }

    const docDefinition: any = {
      pageSize: 'A4',
      pageOrientation: 'portrait',
      pageMargins: [15, 15, 15, 25],
      content,
      footer: (currentPage: number, pageCount: number) =>
        pageCount > 1
          ? { text: `${currentPage} / ${pageCount}`, alignment: 'center', fontSize: 7, margin: [0, 8, 0, 0] }
          : null,
      styles: {
        title: { fontSize: 12, bold: true },
        subtitle: { fontSize: 7 },
        tableHeader: { fontSize: 6.5, bold: true },
        tableCell: { fontSize: 6.5 },
      },
      defaultStyle: { fontSize: 6.5 },
    }

    const stamp = new Date().toISOString().replace(/[-:T]/g, '_').slice(0, 19)
    const fileName = `${stamp}-PICKLIST-${userName}.pdf`

    // Return the pdfmake document handle instead of triggering a download here, so
    // the caller can preview it, download it (pdf.download), or push it to a server
    // printer (pdf.getBase64 → /api/print/picklist). See PicklistGenerateModal.vue.
    const pdf = pdfMake.createPdf(docDefinition)

    return { ok: true, pdf, fileName, count: aggregated.length, docs: relatedDocNos.length, orderedShipments }
  }

  return { generate }
}
