// ai-extract.jsx — reads an attached invoice ON THIS COMPUTER and guesses the fields.
// Uses pdf.js for digital PDFs (fast, accurate) and Tesseract OCR for photos/scans.
// Nothing is sent anywhere — the reader downloads once, then the file is read locally.

function havenLoadScript(src, globalKey) {
  if (window[globalKey]) return Promise.resolve();
  if (!window.__havenScriptPromises) window.__havenScriptPromises = {};
  if (!window.__havenScriptPromises[src]) {
    window.__havenScriptPromises[src] = new Promise((resolve, reject) => {
      const s = document.createElement('script');
      s.src = src;
      s.onload = resolve;
      s.onerror = () => { delete window.__havenScriptPromises[src]; reject(new Error('load failed: ' + src)); };
      document.head.appendChild(s);
    });
  }
  return window.__havenScriptPromises[src];
}

async function havenOcrImage(src) {
  await havenLoadScript('https://unpkg.com/tesseract.js@5.1.1/dist/tesseract.min.js', 'Tesseract');
  const { data } = await window.Tesseract.recognize(src, 'eng');
  return (data && data.text) || '';
}

async function havenExtractText(file) {
  const isPdf = /pdf/i.test(file.type) || /\.pdf$/i.test(file.name);
  if (isPdf) {
    await havenLoadScript('https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.min.js', 'pdfjsLib');
    window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.worker.min.js';
    const buf = await file.arrayBuffer();
    const pdf = await window.pdfjsLib.getDocument({ data: buf }).promise;
    let text = '';
    const pages = Math.min(pdf.numPages, 2);
    for (let i = 1; i <= pages; i++) {
      const page = await pdf.getPage(i);
      const tc = await page.getTextContent();
      text += tc.items.map((it) => it.str).join('\n') + '\n';
    }
    if (text.replace(/\s/g, '').length >= 40) return text;   // digital PDF — done
    // scanned PDF → draw page 1 and OCR it
    const page = await pdf.getPage(1);
    const vp = page.getViewport({ scale: 2 });
    const canvas = document.createElement('canvas');
    canvas.width = vp.width; canvas.height = vp.height;
    await page.render({ canvasContext: canvas.getContext('2d'), viewport: vp }).promise;
    return await havenOcrImage(canvas);
  }
  return await havenOcrImage(file);   // photo / image
}

function havenParseInvoice(text) {
  const t = String(text || '').replace(/\r/g, '');
  const lower = t.toLowerCase();
  const out = {};

  // provider — best evidence is one of YOUR known providers named in the file
  const prov = Store.doc.providers.find((p) =>
    (p.name && p.name.length > 4 && lower.includes(p.name.toLowerCase())) ||
    (p.short && p.short.length > 4 && lower.includes(p.short.toLowerCase())));
  if (prov) { out.provider = prov.name; out.cat = prov.cat; }
  else {
    const firstLine = t.split('\n').map((s) => s.trim()).find((s) => s.length > 3 && s.length < 60 && !/tax invoice|invoice|receipt|abn|gst|statement/i.test(s));
    if (firstLine) out.provider = firstLine;
  }

  // amount — prefer a "total" line, else the largest dollar figure
  let m = t.match(/total[^\n$]{0,30}\$?\s*([\d,]+\.\d{2})/i);
  if (!m) {
    const all = [...t.matchAll(/\$\s*([\d,]+\.\d{2})/g)].map((x) => parseFloat(x[1].replace(/,/g, '')));
    if (all.length) m = [null, String(Math.max.apply(null, all))];
  }
  if (m) { const v = parseFloat(String(m[1]).replace(/,/g, '')); if (v > 0 && v < 100000) out.amount = v; }

  // invoice / receipt number
  const inv = t.match(/(?:invoice|receipt|inv)\s*(?:no\.?|number|#)?\s*[:\-]?\s*([A-Z]{0,5}[-]?\d{2,}[A-Z0-9-]*)/i);
  if (inv) out.id = inv[1].trim().slice(0, 20);

  // date — 10/06/2026 or 10 June 2026 styles
  const mNames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
  const d1 = t.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](20\d{2})/);
  const d2 = t.match(/(\d{1,2})(?:st|nd|rd|th)?\s+(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\s+(20\d{2})/i);
  if (d1) out.date = d1[3] + '-' + String(d1[2]).padStart(2, '0') + '-' + String(d1[1]).padStart(2, '0');
  else if (d2) {
    const mi = mNames.indexOf(d2[2].toLowerCase());
    if (mi >= 0) out.date = d2[3] + '-' + String(mi + 1).padStart(2, '0') + '-' + String(d2[1]).padStart(2, '0');
  }

  return out;
}

// returns { provider?, cat?, amount?, id?, date? } or null if unreadable
async function extractInvoiceFields(file) {
  try {
    const text = await havenExtractText(file);
    if (!text || text.trim().length < 10) return null;
    const out = havenParseInvoice(text);
    return Object.keys(out).length ? out : null;
  } catch (e) { return null; }
}

Object.assign(window, { extractInvoiceFields });
