/**
 * Background processing for one inbox document: run the extraction pipeline on
 * the PDF bytes and persist the result (status → parsed) or the error
 * (status → error) via the REST store. Called fire-and-forget from upload (with
 * the in-memory buffer) and reparse (buffer re-fetched from Strapi). Never throws.
 *
 * The captured ctx carries the iDempiere token obtained at request time; OCR jobs
 * finish well within the token lifetime.
 */
import crypto from 'node:crypto'
import { setInboxParsed, setInboxError, findInboxDocumentsBySize, type InboxCtx } from './inboxDb'
import { runPipeline } from './extractPipeline'
import { renderThumbDataUrl } from './rasterizePdf'

export const processInboxDocument = async (
  ctx: InboxCtx, id: number, pdf: Buffer, meta: { mimeType?: string; filename?: string } = {}
): Promise<void> => {
  try {
    const res = await runPipeline(pdf, { ctx, mimeType: meta.mimeType, filename: meta.filename })
    // page-1 thumbnail for the inbox cards (Strapi can't thumbnail PDFs); best-effort
    let thumb = ''
    if (!/xml/i.test(meta.mimeType || '')) { try { thumb = await renderThumbDataUrl(pdf) } catch {} }
    const extracted: any = thumb ? { ...(res.extracted || {}), __thumb: thumb } : { ...(res.extracted || {}) }

    // File signature + duplicate-upload guard: the same bytes (sha256; for rows stored
    // before the hash existed: same size + file name) already in the inbox → flag it so
    // the list/review can warn instead of offering a second booking. Non-blocking, fail-soft.
    const sha256 = crypto.createHash('sha256').update(pdf).digest('hex')
    extracted.__file = { sha256, size: pdf.length }
    try {
      const twins = await findInboxDocumentsBySize(ctx, pdf.length, id)
      const twin = twins.find((d: any) => d.extracted?.__file?.sha256
        ? d.extracted.__file.sha256 === sha256
        : (d.filename && d.filename === meta.filename))
      if (twin) extracted.__duplicateOf = { id: twin.id, status: twin.status, cInvoiceId: twin.cInvoiceId || null, filename: twin.filename }
    } catch {}
    await setInboxParsed(ctx, id, {
      sourceTier: res.sourceTier,
      vendorFingerprint: res.vendorFingerprint,
      extracted,
      confidence: res.confidence,
      bbox: res.bbox
    })
  } catch (e: any) {
    try { await setInboxError(ctx, id, e?.message || 'Processing failed') } catch {}
  }
}

export default processInboxDocument
