/* NutriDMS, GS1 & Barcodes (Master PRD §5–§11)
   Dashboard · Company Prefixes · GTIN Registry · Barcode Generator · Validation Logs.
   Real client-side barcode (bwip-js) + QR (qrcode) rendering. */

const { useState: useGsState, useEffect: useGsEffect, useMemo: useGsMemo, useRef: useGsRef } = React;

/* ───────── Real barcode (bwip-js) ───────── */
function Barcode({ type, value, scale = 2, height = 12 }) {
  const ref = useGsRef(null);
  const [err, setErr] = useGsState(null);
  useGsEffect(() => {
    const cv = ref.current; if (!cv) return;
    const meta = (typeof BARCODE_TYPES !== "undefined" && BARCODE_TYPES[type]) || { bwip: "code128" };
    try {
      setErr(null);
      // ITF-14/UPC-A/EAN-13 want the GTIN without the check digit appended by the symbology,
      // but bwip-js recomputes, pass the body for those, full for gs1-128.
      let text = String(value);
      if (meta.bwip === "upca") text = text.slice(0, 11);
      else if (meta.bwip === "ean13") text = text.slice(0, 12);
      else if (meta.bwip === "itf14") text = text.slice(0, 13);
      else if (meta.bwip === "gs1-128") text = `(01)${String(value).padStart(14, "0")}`;
      window.bwipjs.toCanvas(cv, {
        bcid: meta.bwip, text, scale, height,
        includetext: true, textxalign: "center", textsize: 9,
        backgroundcolor: "FFFFFF", paddingwidth: 6, paddingheight: 4,
      });
    } catch (e) { setErr(e.message || "Render error"); }
  }, [type, value, scale, height]);
  return (
    <div className="gs-bc">
      <canvas ref={ref} className="gs-bc-cv" style={{ display: err ? "none" : "block" }} />
      {err && <div className="gs-bc-err"><Icon name="alert-triangle" size={13} /> {err}</div>}
    </div>
  );
}

/* ───────── Real QR (qrcodejs, renders into a div) ───────── */
function QR({ value, size = 132 }) {
  const ref = useGsRef(null);
  useGsEffect(() => {
    const el = ref.current; if (!el || !window.QRCode) return;
    el.innerHTML = "";
    try {
      new window.QRCode(el, { text: String(value), width: size, height: size, colorDark: "#15281c", colorLight: "#ffffff", correctLevel: window.QRCode.CorrectLevel.M });
    } catch (e) {}
  }, [value, size]);
  return <div ref={ref} className="gs-qr-cv" style={{ width: size, height: size }} />;
}

function gsCanEdit(role) { return role === "admin" || role === "super-admin"; }
function gsRoleName(role) { try { return window.currentUser ? window.currentUser(role).name : "You"; } catch (e) { return "You"; } }

/* ───────── Assign-GTIN slide panel ───────── */
function GsAssignPanel({ onClose, onDone, role }) {
  const s = gs1State();
  const offerings = useGsMemo(() => {
    const list = (typeof ofLoad === "function") ? ofLoad() : (typeof OFFERINGS !== "undefined" ? OFFERINGS : []);
    return (list || []).filter((o) => o.type === "product" || o.type === "combo" || o.type === "catering");
  }, []);
  const [offeringId, setOfferingId] = useGsState(offerings[0] ? offerings[0].id : "");
  const [prefixId, setPrefixId] = useGsState(s.prefixes[0] ? s.prefixes[0].id : "");
  const [gtinType, setGtinType] = useGsState("gtin_12");
  const pfx = s.prefixes.find((p) => p.id === prefixId);
  const refLen = pfx ? gs1ItemRefLen(gtinType, pfx.prefixLength) : 0;
  const [itemRef, setItemRef] = useGsState("");
  const [indicator, setIndicator] = useGsState("1");
  const [err, setErr] = useGsState(null);

  useGsEffect(() => { if (pfx) setItemRef(gs1NextItemRef(gtinType, pfx.prefixLength)); }, [gtinType, prefixId]);

  // live preview of the GTIN that will be generated
  const preview = useGsMemo(() => {
    if (!pfx || itemRef.length !== refLen) return null;
    try {
      if (gtinType === "gtin_12") return gs1GenerateGTIN12(pfx.prefix, itemRef);
      if (gtinType === "gtin_13") return gs1GenerateGTIN13(pfx.prefix, itemRef);
      return gs1GenerateGTIN14(indicator, pfx.prefix, itemRef);
    } catch (e) { return null; }
  }, [pfx, itemRef, gtinType, indicator, refLen]);

  const save = () => {
    const off = offerings.find((o) => o.id === offeringId);
    const r = gs1AssignGTIN({ offeringId, offeringName: off ? off.name : offeringId, prefixId, gtinType, itemReference: itemRef, indicator, assignedBy: gsRoleName(role) });
    if (!r.ok) { setErr(r.reason); return; }
    onDone(r.rec);
  };

  return (
    <div className="of-panel-scrim" onClick={onClose}>
      <div className="of-panel" onClick={(e) => e.stopPropagation()}>
        <div className="of-panel-h">
          <div><div className="of-panel-t">Assign GTIN</div><div className="of-panel-sub">Generates a unique, check-digit-valid GTIN</div></div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="of-panel-body">
          <label className="gs-field"><span>Product offering</span>
            <select value={offeringId} onChange={(e) => setOfferingId(e.target.value)}>
              {offerings.length === 0 && <option value="">No product offerings yet</option>}
              {offerings.map((o) => <option key={o.id} value={o.id}>{o.name}</option>)}
            </select>
          </label>
          <label className="gs-field"><span>Company prefix</span>
            <select value={prefixId} onChange={(e) => setPrefixId(e.target.value)}>
              {s.prefixes.map((p) => <option key={p.id} value={p.id}>{p.prefix} · {p.prefixLength}-digit</option>)}
            </select>
          </label>
          <div className="gs-field"><span>GTIN type</span>
            <div className="gs-seg">
              {Object.keys(GTIN_TYPES).map((k) => (
                <button key={k} className={`gs-seg-btn ${gtinType === k ? "on" : ""}`} onClick={() => setGtinType(k)}>{GTIN_TYPES[k].label}</button>
              ))}
            </div>
            <div className="gs-hint">{GTIN_TYPES[gtinType].desc}</div>
          </div>
          {gtinType === "gtin_14" && (
            <label className="gs-field"><span>Indicator digit (packaging level)</span>
              <select value={indicator} onChange={(e) => setIndicator(e.target.value)}>
                {["1", "2", "3", "4", "5"].map((d) => <option key={d} value={d}>{d}, {d === "1" ? "inner pack" : d === "2" ? "case" : d === "3" ? "carton" : "pallet level " + d}</option>)}
              </select>
            </label>
          )}
          <label className="gs-field"><span>Item reference ({refLen} digit{refLen === 1 ? "" : "s"})</span>
            <input value={itemRef} onChange={(e) => { setItemRef(e.target.value.replace(/\D/g, "").slice(0, refLen)); setErr(null); }} inputMode="numeric" placeholder={"0".repeat(Math.max(refLen, 1))} />
            <div className="gs-hint">Next available reference is pre-filled. The check digit is added automatically.</div>
          </label>

          <div className="gs-preview">
            <div className="gs-preview-lbl">Generated GTIN</div>
            {preview ? (
              <>
                <div className="gs-preview-gtin">{preview}<span className="gs-preview-cd" title="Check digit">{preview.slice(-1)}</span></div>
                <Barcode type={GTIN_TYPES[gtinType].barcode} value={preview} />
              </>
            ) : <div className="gs-preview-empty">Complete the item reference to preview the GTIN + barcode.</div>}
          </div>
          {err && <div className="gs-error"><Icon name="alert-circle" size={14} /> {err}</div>}
        </div>
        <div className="of-panel-foot">
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!preview} onClick={save}><Icon name="check" size={15} /> Assign GTIN</button>
        </div>
      </div>
    </div>
  );
}

/* ───────── Add-prefix slide panel ───────── */
function GsPrefixPanel({ onClose, onDone }) {
  const [prefix, setPrefix] = useGsState("");
  const [err, setErr] = useGsState(null);
  const len = prefix.length;
  const valid = len >= 6 && len <= 11;
  const save = () => {
    const r = gs1AddPrefix(prefix, len);
    if (!r.ok) { setErr(r.reason); return; }
    onDone(r.rec);
  };
  return (
    <div className="of-panel-scrim" onClick={onClose}>
      <div className="of-panel sm" onClick={(e) => e.stopPropagation()}>
        <div className="of-panel-h">
          <div><div className="of-panel-t">Add Company Prefix</div><div className="of-panel-sub">Issued by GS1 to your organization</div></div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="of-panel-body">
          <label className="gs-field"><span>GS1 company prefix</span>
            <input value={prefix} onChange={(e) => { setPrefix(e.target.value.replace(/\D/g, "").slice(0, 11)); setErr(null); }} inputMode="numeric" placeholder="0628176" />
            <div className="gs-hint">{len} digit{len === 1 ? "" : "s"} · capacity {valid ? Math.pow(10, 11 - len).toLocaleString() + " GTIN-12s" : "—"}</div>
          </label>
          {err && <div className="gs-error"><Icon name="alert-circle" size={14} /> {err}</div>}
        </div>
        <div className="of-panel-foot">
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!valid} onClick={save}><Icon name="plus" size={15} /> Add prefix</button>
        </div>
      </div>
    </div>
  );
}

/* ───────── Barcode detail popup (rolling hard popup) ───────── */
function GsBarcodePop({ rec, onClose }) {
  const meta = BARCODE_TYPES[rec.barcodeType] || {};
  const download = () => {
    const cv = document.querySelector(".gs-pop .gs-bc-cv");
    if (!cv) return;
    const a = document.createElement("a"); a.href = cv.toDataURL("image/png");
    a.download = `barcode-${rec.encodedValue}-${rec.barcodeType}.png`; a.click();
  };
  return (
    <div className="gs-pop-scrim" onClick={onClose}>
      <div className="gs-pop" onClick={(e) => e.stopPropagation()}>
        <div className="gs-pop-h"><span className="pill brand" style={{ fontSize: 11 }}>{meta.label}</span><button className="icon-btn" onClick={onClose}><Icon name="x" size={17} /></button></div>
        <div className="gs-pop-nm">{rec.offeringName}</div>
        <Barcode type={rec.barcodeType} value={rec.encodedValue} scale={3} height={16} />
        <div className="gs-pop-meta"><span>Encoded value</span><b>{rec.encodedValue}</b></div>
        <div className="gs-pop-meta"><span>Use</span><b>{meta.use}</b></div>
        <button className="btn secondary sm" onClick={download}><Icon name="download" size={14} /> Download PNG</button>
      </div>
    </div>
  );
}

/* ───────── Main screen ───────── */
function Gs1Barcodes() {
  const { role, toast } = useApp();
  const canEdit = gsCanEdit(role);
  const [tab, setTab] = useGsState("dashboard");
  const [, bump] = useGsState(0);
  const [assign, setAssign] = useGsState(false);
  const [addPrefix, setAddPrefix] = useGsState(false);
  const [pop, setPop] = useGsState(null);
  useGsEffect(() => {
    const h = () => bump((n) => n + 1);
    window.addEventListener("nutridms-gs1-data", h);
    return () => window.removeEventListener("nutridms-gs1-data", h);
  }, []);
  const s = gs1State();

  const genBarcodeFor = (g, type) => {
    const r = gs1GenerateBarcode({ gtinId: g.id, barcodeType: type, who: gsRoleName(role) });
    if (r.ok) toast(`${BARCODE_TYPES[type].label} barcode generated`);
  };

  const TABS = [
    { id: "dashboard", label: "Dashboard", icon: "layout-dashboard" },
    { id: "prefixes", label: "Company Prefixes", icon: "building-2" },
    { id: "registry", label: "GTIN Registry", icon: "list-ordered" },
    { id: "generator", label: "Barcode Generator", icon: "scan-barcode" },
    { id: "logs", label: "Validation Logs", icon: "scroll-text" },
  ];

  return (
    <div className="gs-screen">
      <div className="page-head">
        <div>
          <h1 className="page-title">GS1 &amp; Barcodes</h1>
          <p className="page-sub">Company prefixes, GTIN assignment, and scannable barcode &amp; QR generation.</p>
        </div>
        <div className="page-head-actions">
          {canEdit && tab !== "logs" && (
            <button className="btn primary" onClick={() => setAssign(true)}><Icon name="plus" size={16} /> Assign GTIN</button>
          )}
        </div>
      </div>

      {!canEdit && (
        <div className="gs-readonly"><Icon name="lock" size={13} /> View-only, GTIN assignment and barcode generation are restricted to Admins and Super Admins.</div>
      )}

      <div className="gs-tabs">
        {TABS.map((t) => (
          <button key={t.id} className={`gs-tab ${tab === t.id ? "on" : ""}`} onClick={() => setTab(t.id)}>
            <Icon name={t.icon} size={15} /> {t.label}
            {t.id === "registry" && <span className="gs-tab-c">{s.gtins.length}</span>}
            {t.id === "generator" && <span className="gs-tab-c">{s.barcodes.length}</span>}
          </button>
        ))}
      </div>

      {tab === "dashboard" && <GsDashboard s={s} setTab={setTab} />}
      {tab === "prefixes" && <GsPrefixes s={s} canEdit={canEdit} onAdd={() => setAddPrefix(true)} />}
      {tab === "registry" && <GsRegistry s={s} canEdit={canEdit} onGen={genBarcodeFor} onAssign={() => setAssign(true)} />}
      {tab === "generator" && <GsGenerator s={s} canEdit={canEdit} onGen={genBarcodeFor} onPop={setPop} role={role} toast={toast} />}
      {tab === "logs" && <GsLogs s={s} />}

      {assign && <GsAssignPanel role={role} onClose={() => setAssign(false)} onDone={() => { setAssign(false); setTab("registry"); toast("GTIN assigned"); }} />}
      {addPrefix && <GsPrefixPanel onClose={() => setAddPrefix(false)} onDone={() => { setAddPrefix(false); toast("Company prefix added"); }} />}
      {pop && <GsBarcodePop rec={pop} onClose={() => setPop(null)} />}
    </div>
  );
}

/* ── Dashboard ── */
function GsDashboard({ s, setTab }) {
  const expiringSoon = s.prefixes.filter((p) => p.renewalDate && new Date(p.renewalDate) < new Date("2026-09-01")).length;
  const cards = [
    { k: "GTINs assigned", v: s.gtins.length, ic: "list-ordered", tab: "registry", tone: "brand" },
    { k: "Barcodes generated", v: s.barcodes.length, ic: "scan-barcode", tab: "generator", tone: "violet" },
    { k: "QR codes", v: s.qrs.length, ic: "qr-code", tab: "generator", tone: "amber" },
    { k: "Company prefixes", v: s.prefixes.length, ic: "building-2", tab: "prefixes", tone: "green" },
  ];
  return (
    <div className="gs-dash">
      <div className="gs-stat-row">
        {cards.map((c) => (
          <button key={c.k} className={`gs-stat ${c.tone}`} onClick={() => setTab(c.tab)}>
            <span className="gs-stat-ic"><Icon name={c.ic} size={18} /></span>
            <span className="gs-stat-v">{c.v}</span>
            <span className="gs-stat-k">{c.k}</span>
          </button>
        ))}
      </div>
      <div className="gs-dash-grid">
        <div className="gs-card">
          <div className="gs-card-h"><Icon name="history" size={15} /> Recent activity</div>
          <div className="gs-acts">
            {s.logs.slice(0, 5).map((l) => (
              <div key={l.id} className="gs-act">
                <span className={`gs-act-dot ${l.result}`}></span>
                <div className="gs-act-tx"><b>{l.note}</b><small>{l.who} · {l.at}</small></div>
                <span className={`pill ${l.result === "pass" ? "success" : "danger"}`} style={{ fontSize: 10 }}>{l.result}</span>
              </div>
            ))}
          </div>
        </div>
        <div className="gs-card">
          <div className="gs-card-h"><Icon name="building-2" size={15} /> Prefix capacity</div>
          {s.prefixes.map((p) => {
            const used = s.gtins.filter((g) => g.companyPrefixId === p.id).length;
            const pct = Math.min(100, (used / p.capacity) * 100);
            return (
              <div key={p.id} className="gs-cap">
                <div className="gs-cap-top"><b>{p.prefix}</b><span>{used.toLocaleString()} / {p.capacity.toLocaleString()}</span></div>
                <div className="gs-cap-bar"><span style={{ width: Math.max(pct, 1.5) + "%" }}></span></div>
                {expiringSoon > 0 && p.renewalDate && <div className="gs-cap-renew"><Icon name="calendar-clock" size={11} /> Renews {p.renewalDate}</div>}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

/* ── Company Prefixes ── */
function GsPrefixes({ s, canEdit, onAdd }) {
  return (
    <div className="gs-card">
      <div className="gs-card-h">
        <Icon name="building-2" size={15} /> Company Prefixes
        <div className="grow" />
        {canEdit && <button className="btn secondary sm" onClick={onAdd}><Icon name="plus" size={14} /> Add prefix</button>}
      </div>
      <table className="gs-table">
        <thead><tr><th>Prefix</th><th>Length</th><th>Capacity</th><th>License</th><th>Renewal</th></tr></thead>
        <tbody>
          {s.prefixes.map((p) => (
            <tr key={p.id}>
              <td className="gs-mono">{p.prefix}</td>
              <td>{p.prefixLength}-digit</td>
              <td>{p.capacity.toLocaleString()}</td>
              <td><span className="pill success" style={{ fontSize: 10 }}>{p.licenseStatus}</span></td>
              <td>{p.renewalDate || "—"}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

/* ── GTIN Registry ── */
function GsRegistry({ s, canEdit, onGen, onAssign }) {
  const [q, setQ] = useGsState("");
  const rows = s.gtins.filter((g) => !q || g.gtin.includes(q) || (g.offeringName || "").toLowerCase().includes(q.toLowerCase()));
  return (
    <div className="gs-card">
      <div className="gs-card-h">
        <Icon name="list-ordered" size={15} /> GTIN Registry
        <div className="grow" />
        <div className="gs-search"><Icon name="search" size={14} /><input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search GTIN or product…" /></div>
      </div>
      <table className="gs-table">
        <thead><tr><th>GTIN</th><th>Type</th><th>Product</th><th>Check</th><th>Status</th><th>Assigned</th>{canEdit && <th></th>}</tr></thead>
        <tbody>
          {rows.map((g) => {
            const hasBc = s.barcodes.some((b) => b.gtinId === g.id);
            return (
              <tr key={g.id}>
                <td className="gs-mono">{g.gtin}</td>
                <td>{GTIN_TYPES[g.gtinType].label}</td>
                <td>{g.offeringName}</td>
                <td className="gs-mono">{g.checkDigit}</td>
                <td><span className="pill neutral" style={{ fontSize: 10 }}>{g.status}</span></td>
                <td>{g.assignedBy}<br /><small style={{ color: "var(--gray-500)" }}>{g.assignedAt}</small></td>
                {canEdit && <td>{!hasBc
                  ? <button className="btn ghost sm" onClick={() => onGen(g, GTIN_TYPES[g.gtinType].barcode)}><Icon name="scan-barcode" size={13} /> Generate</button>
                  : <span className="gs-done"><Icon name="check" size={13} /> Barcode</span>}</td>}
              </tr>
            );
          })}
          {rows.length === 0 && <tr><td colSpan={canEdit ? 7 : 6} className="gs-empty">No GTINs match. {canEdit && <button className="btn ghost sm" onClick={onAssign}>Assign one →</button>}</td></tr>}
        </tbody>
      </table>
    </div>
  );
}

/* ── Barcode Generator (gallery + QR) ── */
function GsGenerator({ s, canEdit, onGen, onPop, role, toast }) {
  const offerings = useGsMemo(() => {
    const list = (typeof ofLoad === "function") ? ofLoad() : (typeof OFFERINGS !== "undefined" ? OFFERINGS : []);
    return list || [];
  }, [s]);
  const [qrOffering, setQrOffering] = useGsState(offerings[0] ? offerings[0].id : "");
  const [qrType, setQrType] = useGsState("nutrition_panel");
  const addQR = () => {
    const off = offerings.find((o) => o.id === qrOffering);
    gs1AddQR({ offeringId: qrOffering, offeringName: off ? off.name : qrOffering, qrType, who: gsRoleName(role) });
    toast(`${QR_TYPES[qrType].label} QR generated`);
  };
  return (
    <div className="gs-gen">
      <div className="gs-card">
        <div className="gs-card-h"><Icon name="scan-barcode" size={15} /> Generated barcodes</div>
        <div className="gs-bc-grid">
          {s.barcodes.map((b) => (
            <button key={b.id} className="gs-bc-card" onClick={() => onPop(b)}>
              <Barcode type={b.barcodeType} value={b.encodedValue} />
              <div className="gs-bc-card-nm">{b.offeringName}</div>
              <div className="gs-bc-card-meta"><span className="pill brand" style={{ fontSize: 10 }}>{BARCODE_TYPES[b.barcodeType].label}</span><span className="gs-mono">{b.encodedValue}</span></div>
            </button>
          ))}
          {s.barcodes.length === 0 && <div className="gs-empty">No barcodes yet, generate one from the GTIN Registry.</div>}
        </div>
      </div>

      <div className="gs-card">
        <div className="gs-card-h"><Icon name="qr-code" size={15} /> QR codes</div>
        {canEdit && (
          <div className="gs-qr-builder">
            <select value={qrOffering} onChange={(e) => setQrOffering(e.target.value)}>
              {offerings.map((o) => <option key={o.id} value={o.id}>{o.name}</option>)}
            </select>
            <select value={qrType} onChange={(e) => setQrType(e.target.value)}>
              {Object.keys(QR_TYPES).map((k) => <option key={k} value={k}>{QR_TYPES[k].label}</option>)}
            </select>
            <button className="btn secondary sm" onClick={addQR}><Icon name="plus" size={14} /> Generate QR</button>
          </div>
        )}
        <div className="gs-qr-grid">
          {s.qrs.map((q) => (
            <div key={q.id} className="gs-qr-card">
              <QR value={q.encodedUrl} />
              <div className="gs-qr-card-nm">{q.offeringName}</div>
              <span className="pill amber" style={{ fontSize: 10 }}><Icon name={QR_TYPES[q.qrType].icon} size={11} /> {QR_TYPES[q.qrType].label}</span>
            </div>
          ))}
          {s.qrs.length === 0 && <div className="gs-empty">No QR codes yet.</div>}
        </div>
      </div>
    </div>
  );
}

/* ── Validation Logs ── */
function GsLogs({ s }) {
  const kindMeta = { assign: { ic: "tag", c: "brand" }, generate: { ic: "scan-barcode", c: "violet" }, validate: { ic: "shield-check", c: "green" }, duplicate: { ic: "copy-x", c: "red" }, qr: { ic: "qr-code", c: "amber" } };
  return (
    <div className="gs-card">
      <div className="gs-card-h"><Icon name="scroll-text" size={15} /> Validation Logs</div>
      <table className="gs-table">
        <thead><tr><th>When</th><th>Event</th><th>Target</th><th>By</th><th>Result</th></tr></thead>
        <tbody>
          {s.logs.map((l) => {
            const m = kindMeta[l.kind] || { ic: "circle", c: "neutral" };
            return (
              <tr key={l.id}>
                <td style={{ whiteSpace: "nowrap" }}>{l.at}</td>
                <td><span className={`gs-evt ${m.c}`}><Icon name={m.ic} size={12} /> {l.note}</span></td>
                <td className="gs-mono">{l.target}</td>
                <td>{l.who}</td>
                <td><span className={`pill ${l.result === "pass" ? "success" : "danger"}`} style={{ fontSize: 10 }}>{l.result}</span></td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

if (typeof window !== "undefined") { window.Gs1Barcodes = Gs1Barcodes; window.Barcode = Barcode; window.QR = QR; }
