/* NutriDMS, Offerings (PRD §9/§10)
   List · Create (type-aware) · Detail/builder with live nutrition aggregation. */

const { useState: useOfState, useEffect: useOfEffect, useMemo: useOfMemo } = React;

function OfPill({ status }) {
  const meta = (typeof OFFERING_STATUS !== "undefined" && OFFERING_STATUS[status]) || { label: status, tone: "neutral" };
  return <span className={`pill ${meta.tone}`} style={{ fontSize: 11 }}>{meta.label}</span>;
}

/* ── Nutrition table (per serving / total / per 100g, or a single totals row) ── */
function OfNutrTable({ cols }) {
  // cols: [{ label, totals }]
  const keys = (typeof OF_NUTRIENTS !== "undefined") ? OF_NUTRIENTS : [];
  const nice = {
    energy_kcal: "Calories", fat_g: "Fat (g)", fat_saturated_g: "Saturated (g)",
    carbohydrate_g: "Carbs (g)", fibre_g: "Fibre (g)", sugars_g: "Sugars (g)",
    protein_g: "Protein (g)", sodium_mg: "Sodium (mg)",
  };
  return (
    <table className="of-nutr">
      <thead><tr><th>Nutrient</th>{cols.map((c, i) => <th key={i}>{c.label}</th>)}</tr></thead>
      <tbody>
        {keys.map((k) => (
          <tr key={k}>
            <td className="of-nutr-k">{nice[k] || k}</td>
            {cols.map((c, i) => <td key={i} className="of-nutr-v">{Math.round((c.totals[k] || 0) * 10) / 10}</td>)}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

function OfAllergenMatrix({ components }) {
  const m = (typeof ofAllergenMatrix === "function") ? ofAllergenMatrix(components) : { allergens: [], rows: [] };
  if (!m.allergens.length) return <div className="of-empty-inline">No priority allergens detected across components.</div>;
  return (
    <div className="of-matrix-wrap">
      <table className="of-matrix">
        <thead><tr><th>Component</th>{m.allergens.map((a) => <th key={a}>{a}</th>)}</tr></thead>
        <tbody>
          {m.rows.map((r, i) => (
            <tr key={i}>
              <td className="of-matrix-nm">{r.name}</td>
              {m.allergens.map((a) => (
                <td key={a} className="of-matrix-cell">{r.present[a] ? <Icon name="check" size={13} stroke={2.8} /> : <span className="of-matrix-dot">·</span>}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

/* ───────── Create panel (right slide) ───────── */
function OfCreatePanel({ onClose, onCreate }) {
  const [step, setStep] = useOfState(() => window.__ofCreateType ? 2 : 1);
  const [type, setType] = useOfState(() => window.__ofCreateType || null);
  const [name, setName] = useOfState("");
  const types = (typeof OFFERING_TYPES !== "undefined") ? OFFERING_TYPES : [];
  const recipes = (typeof ofRecipes === "function") ? ofRecipes() : [];
  // Products may only source APPROVED / published recipes (PRD Step 2).
  const isApproved = (r) => r.status === "approved" || r.status === "published";
  const approvedRecipes = recipes.filter(isApproved);
  const [single, setSingle] = useOfState((approvedRecipes[0] || recipes[0] || {}).id || null);
  const [components, setComponents] = useOfState([]);
  const [guestCount, setGuestCount] = useOfState(50);
  // Product setup (PRD Step 2)
  const [psetup, setPsetup] = useOfState({ category: "", brand: "", servingSize: "", servingUnit: "g", servingWeight: 250, servingsPerContainer: 1, packageType: "", langMode: "Bilingual" });
  const setPs = (k, v) => setPsetup((s) => ({ ...s, [k]: v }));
  const t = type ? (typeof ofType === "function" ? ofType(type) : null) : null;
  const PKG_TYPES = (typeof PS_PACKAGE_TYPES !== "undefined") ? PS_PACKAGE_TYPES : ["Pouch", "Tray + film", "Bottle", "Jar", "Carton", "Can", "Cup", "Bag", "Box"];
  const PCATS = (typeof PS_CATEGORIES !== "undefined") ? PS_CATEGORIES : ["Bakery", "Beverages", "Dairy & Alternatives", "Frozen", "Prepared Meals", "Snacks"];

  const addComponent = () => setComponents((c) => [...c, { recipeId: recipes[0] ? recipes[0].id : null, qty: 1 }]);
  const setComp = (i, patch) => setComponents((c) => c.map((x, j) => j === i ? { ...x, ...patch } : x));
  const rmComp = (i) => setComponents((c) => c.filter((_, j) => j !== i));

  const canSave = type && name.trim() && (
    (t && t.single) ? !!single :
    type === "meal-plan" ? true :
    components.length > 0
  );

  const save = () => {
    const base = { id: ofNewId(), type, name: name.trim(), status: "draft", owner: "You", updated: new Date().toISOString().slice(0, 10) };
    if (t && t.single) {
      base.single = single;
      base.servings = (type === "product" ? (psetup.servingsPerContainer || 1) : 1);
      if (type === "product") {
        base.single = { recipeId: single, servingG: psetup.servingWeight || 250 };
        base.category = psetup.category; base.brand = psetup.brand; base.langMode = psetup.langMode; base.jurisdiction = "Canada";
      } else {
        base.single = single;
      }
    }
    else if (type === "combo") base.components = components;
    else if (type === "catering") { base.components = components; base.guestCount = guestCount; base.perTray = 12; }
    else if (type === "meal-plan") base.days = [{ label: "Day 1", meals: components.length ? components.map((c) => ({ recipeId: c.recipeId, qty: c.qty })) : [] }];
    ofSave(base);
    // Seed the product specification with the setup fields so the detail page reflects them.
    if (type === "product" && typeof psPatch === "function") {
      psPatch(base.id, "details", { brandName: psetup.brand, category: psetup.category, servingSizeG: psetup.servingWeight, servingsPerContainer: psetup.servingsPerContainer, servingDescription: psetup.servingSize });
      psPatch(base.id, "packaging", { packageType: psetup.packageType });
    }
    onCreate(base);
  };

  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">{window.__ofCreateType ? `Create ${t ? t.label : "Product"}` : "Create Offering"}</div><div className="of-panel-sub">{window.__ofCreateType ? "Set up the product" : `Step ${step} of 2`}</div></div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>

        {step === 1 && (
          <div className="of-panel-body">
            <div className="of-panel-q">What are you creating?</div>
            <div className="of-type-grid">
              {types.map((tp) => (
                <button key={tp.id} type="button" className={`of-type-card ${type === tp.id ? "on" : ""}`} onClick={() => setType(tp.id)}>
                  <div className="of-type-ic"><Icon name={tp.icon} size={20} /></div>
                  <div className="of-type-nm">{tp.label}</div>
                  <div className="of-type-uc">{tp.useCase}</div>
                </button>
              ))}
            </div>
            {t && (
              <div className="of-outputs">
                <div className="of-outputs-h">Outputs</div>
                <div className="of-outputs-list">{t.outputs.map((o) => <span key={o} className="of-chip"><Icon name="check" size={11} stroke={2.6} /> {o}</span>)}</div>
              </div>
            )}
          </div>
        )}

        {step === 2 && (
          <div className="of-panel-body">
            <label className="of-field"><span>Offering name</span>
              <input value={name} onChange={(e) => setName(e.target.value)} placeholder={`e.g. ${t.label}, ...`} />
            </label>

            {t.single && (
              <label className="of-field"><span>Source recipe (approved only)</span>
                <select value={single || ""} onChange={(e) => setSingle(e.target.value)}>
                  {(type === "product" ? approvedRecipes : recipes).map((r) => <option key={r.id} value={r.id}>{r.name}</option>)}
                </select>
                {type === "product" && approvedRecipes.length === 0 && <div className="of-warn"><Icon name="alert-triangle" size={12} /> No approved recipes available. Only approved recipes can source a product.</div>}
                {type === "product" && approvedRecipes.length > 0 && <div className="of-hint-sm">Pulls ingredients, allergens, nutrition totals, yield &amp; serving size from the approved recipe.</div>}
              </label>
            )}

            {type === "product" && (
              <>
                <div className="of-setup-grid">
                  <label className="of-field"><span>Product category</span>
                    <select value={psetup.category} onChange={(e) => setPs("category", e.target.value)}>
                      <option value="">Select…</option>
                      {PCATS.map((c) => <option key={c} value={c}>{c}</option>)}
                    </select>
                  </label>
                  <label className="of-field"><span>Brand / company</span>
                    <input value={psetup.brand} onChange={(e) => setPs("brand", e.target.value)} placeholder="e.g. Harvest Table" />
                  </label>
                </div>
                <div className="of-setup-grid">
                  <label className="of-field"><span>Serving size</span>
                    <input value={psetup.servingSize} onChange={(e) => setPs("servingSize", e.target.value)} placeholder="e.g. 1 fillet" />
                  </label>
                  <label className="of-field"><span>Serving weight</span>
                    <div className="of-inline">
                      <input type="number" min="1" value={psetup.servingWeight} onChange={(e) => setPs("servingWeight", parseFloat(e.target.value) || 0)} />
                      <select value={psetup.servingUnit} onChange={(e) => setPs("servingUnit", e.target.value)}>{["g", "mL"].map((u) => <option key={u}>{u}</option>)}</select>
                    </div>
                  </label>
                </div>
                <div className="of-setup-grid">
                  <label className="of-field"><span>Servings per container</span>
                    <input type="number" min="1" value={psetup.servingsPerContainer} onChange={(e) => setPs("servingsPerContainer", parseInt(e.target.value) || 1)} />
                  </label>
                  <label className="of-field"><span>Package type</span>
                    <select value={psetup.packageType} onChange={(e) => setPs("packageType", e.target.value)}>
                      <option value="">Select…</option>
                      {PKG_TYPES.map((p) => <option key={p} value={p}>{p}</option>)}
                    </select>
                  </label>
                </div>
                <div className="of-setup-grid">
                  <label className="of-field"><span>Language mode</span>
                    <select value={psetup.langMode} onChange={(e) => setPs("langMode", e.target.value)}>{["English", "French", "Bilingual"].map((l) => <option key={l}>{l}</option>)}</select>
                  </label>
                  <label className="of-field"><span>Jurisdiction</span>
                    <select value="Canada" disabled><option>Canada</option></select>
                  </label>
                </div>
              </>
            )}

            {!t.single && (
              <div className="of-field">
                <span>{type === "meal-plan" ? "Day 1 meals" : "Components"}</span>
                <div className="of-comps">
                  {components.map((c, i) => (
                    <div key={i} className="of-comp">
                      <select value={c.recipeId || ""} onChange={(e) => setComp(i, { recipeId: e.target.value })}>
                        {recipes.map((r) => <option key={r.id} value={r.id}>{r.name}</option>)}
                      </select>
                      <input type="number" min="1" value={c.qty} onChange={(e) => setComp(i, { qty: parseFloat(e.target.value) || 1 })} className="of-comp-qty" />
                      <button className="icon-btn sm" onClick={() => rmComp(i)}><Icon name="trash-2" size={14} /></button>
                    </div>
                  ))}
                  <button className="btn secondary sm" onClick={addComponent}><Icon name="plus" size={14} /> Add component</button>
                </div>
              </div>
            )}

            {type === "catering" && (
              <label className="of-field"><span>Guest count</span>
                <input type="number" min="1" value={guestCount} onChange={(e) => setGuestCount(parseInt(e.target.value) || 1)} />
              </label>
            )}
          </div>
        )}

        <div className="of-panel-foot">
          {step === 2 && <button className="btn ghost" onClick={() => { if (window.__ofCreateType) onClose(); else setStep(1); }}><Icon name="arrow-left" size={14} /> Back</button>}
          <span className="grow" />
          {step === 1
            ? <button className="btn primary" disabled={!type} onClick={() => setStep(2)}>Continue <Icon name="arrow-right" size={14} /></button>
            : <button className="btn primary" disabled={!canSave} onClick={save}><Icon name="check" size={14} /> Create {window.__ofCreateType && t ? t.label : "offering"}</button>}
        </div>
      </div>
    </div>
  );
}

/* ───────── Detail / builder ───────── */
function OfDetail({ offering, onBack }) {
  const { setPage, toast, role } = useApp();
  const t = (typeof ofType === "function") ? ofType(offering.type) : null;
  const recipeName = (id) => { const r = ofRecipeById(id); return r ? r.name : id; };
  const [, psBump] = useOfState(0);
  const bump = () => psBump((n) => n + 1);
  const canEdit = (typeof psCanEdit === "function") ? psCanEdit(role) : true;
  const specOn = (typeof psSettings === "function") ? psSettings().enableProductSpecifications : true;
  // PRD §3, only Product carries the FULL specification. Menu Items get a lighter set.
  const isProduct = offering.type === "product";
  const isMenuItem = offering.type === "menu-item";
  const hasSpec = specOn; // all offering types now use the wizard UI
  const comp = (specOn && isProduct && typeof psCompletion === "function") ? psCompletion(offering) : null;

  // tab set per offering type (PRD §3)
  const tabs = [{ id: "overview", label: "Overview", icon: "layout-dashboard" }];
  if (isProduct && specOn) tabs.push(
    { id: "details", label: "Product Details", icon: "info" },
    { id: "processing", label: "Processing & Yield", icon: "flame" },
    { id: "costing", label: "Cost & Margin", icon: "calculator" },
    { id: "pricing", label: "Pricing", icon: "globe" },
    { id: "packaging", label: "Packaging", icon: "package" },
    { id: "storage", label: "Storage", icon: "thermometer-snowflake" },
    { id: "manufacturing", label: "Manufacturing", icon: "factory" },
    { id: "claims", label: "Claims", icon: "badge-check" },
    { id: "gs1", label: "GS1 / Barcode", icon: "scan-barcode" },
    { id: "qr", label: "Customer Experience", icon: "smartphone" },
    { id: "compliance", label: "Compliance", icon: "shield-check" },
    { id: "pc-summary", label: "Compliance Summary", icon: "clipboard-check" },
    { id: "pc-audit", label: "Audit Trail", icon: "history" },
    { id: "documents", label: "Documents", icon: "folder" },
  );
  else if (isMenuItem && specOn) tabs.push(
    { id: "menu-data", label: "Digital Menu Data", icon: "list", icon2: true },
    { id: "claims", label: "Claims", icon: "badge-check" },
    { id: "qr", label: "Customer Experience", icon: "smartphone" },
    { id: "compliance", label: "Compliance", icon: "shield-check" },
  );
  else if (specOn) tabs.push(
    { id: "claims", label: "Claims", icon: "badge-check" },
    { id: "gs1", label: "GS1 / Barcode", icon: "scan-barcode" },
    { id: "qr", label: "Customer Experience", icon: "smartphone" },
    { id: "pc-summary", label: "Compliance Summary", icon: "clipboard-check" },
    { id: "pc-audit", label: "Audit Trail", icon: "history" },
    { id: "documents", label: "Documents", icon: "folder" },
  );
  const [tab, setTab] = useOfState("overview");
  const [specSheet, setSpecSheet] = useOfState(false);

  const overview = (() => {
    let body = null;
    if (t && t.single) {
    const d = ofSingleDeclarations(offering.single, offering.servings || 1);
    body = (
      <>
        <div className="of-sec-h"><Icon name="calculator" size={15} /> Nutrition declarations</div>
        <OfNutrTable cols={[
          { label: "Per serving", totals: d.perServing },
          { label: "Recipe total", totals: d.recipeTotal },
          { label: "Per 100 g", totals: d.per100g },
        ]} />
        <div className="of-note">Final yield ≈ {d.finalYieldG} g · {d.servings} serving(s).</div>
        {offering.type === "menu-item" && (
          <div className="of-qr-row">
            <div className="of-qr"><Icon name="qr-code" size={64} /></div>
            <div><div className="of-sec-h" style={{ marginTop: 0 }}><Icon name="utensils" size={15} /> Menu board data</div>
              <div className="of-note">Calories: <b>{Math.round(d.perServing.energy_kcal)}</b> · Protein {d.perServing.protein_g} g · Sodium {Math.round(d.perServing.sodium_mg)} mg</div>
              <div className="of-note">QR encodes the digital nutrition panel + allergen declaration.</div>
            </div>
          </div>
        )}
        <div className="of-actions">
          <button className="btn secondary" onClick={() => { try { window.labelStudioSetEnabled && window.labelStudioSetEnabled(true); } catch (e) {} setPage("label-studio"); }}>
            <Icon name="tag" size={15} /> Open in Label Studio
          </button>
        </div>
      </>
    );
  } else if (offering.type === "combo") {
    const total = ofComboTotal(offering.components);
    body = (
      <>
        <div className="of-sec-h"><Icon name="layers" size={15} /> Components</div>
        <ul className="of-complist">{offering.components.map((c, i) => <li key={i}><span>{recipeName(c.recipeId)}</span><span className="of-qtybadge">× {c.qty}</span></li>)}</ul>
        <div className="of-sec-h"><Icon name="calculator" size={15} /> Combined nutrition (Σ component × qty)</div>
        <OfNutrTable cols={[{ label: "Combo total", totals: total }]} />
        <div className="of-sec-h"><Icon name="shield-alert" size={15} /> Allergen matrix</div>
        <OfAllergenMatrix components={offering.components} />
      </>
    );
  } else if (offering.type === "meal-plan") {
    const mp = ofMealPlanTotals(offering.days);
    const allMeals = (offering.days || []).flatMap((d) => d.meals || []);
    body = (
      <>
        <div className="of-sec-h"><Icon name="calendar-range" size={15} /> Daily totals</div>
        <OfNutrTable cols={mp.dayTotals.map((d) => ({ label: d.label, totals: d.total }))} />
        <div className="of-sec-h"><Icon name="trending-up" size={15} /> Weekly average ÷ {mp.days} days</div>
        <OfNutrTable cols={[{ label: "Avg / day", totals: mp.weeklyAverage }]} />
        <div className="of-sec-h"><Icon name="shield-alert" size={15} /> Allergen matrix</div>
        <OfAllergenMatrix components={allMeals} />
      </>
    );
  } else if (offering.type === "catering") {
    const c = ofCateringTotals(offering.components, offering.guestCount, offering.perTray);
    body = (
      <>
        <div className="of-sec-h"><Icon name="users" size={15} /> Scaled for {c.guests} guests (base × guests ÷ servings)</div>
        <OfNutrTable cols={[
          { label: "Per person", totals: c.perPerson },
          { label: `Per tray (${c.tray})`, totals: c.perTray },
          { label: "Group total", totals: c.groupTotal },
        ]} />
        <div className="of-sec-h"><Icon name="shield-alert" size={15} /> Allergen matrix</div>
        <OfAllergenMatrix components={offering.components} />
        <div className="of-sec-h"><Icon name="clipboard-list" size={15} /> Procurement list (scaled to {c.guests})</div>
        <div className="of-proc-wrap">
          <table className="of-proc">
            <thead><tr><th>Recipe</th><th>Ingredient</th><th>Amount</th></tr></thead>
            <tbody>{c.procurement.map((p, i) => <tr key={i}><td>{p.recipe}</td><td className="of-proc-ing">{p.ingredient}</td><td className="of-proc-amt">{p.amount_g} g</td></tr>)}</tbody>
          </table>
        </div>
      </>
    );
    }
    return body;
  })();

  return (
    <div className="page of-page">
      <div className="page-head" style={{ alignItems: "flex-start" }}>
        <div style={{ minWidth: 0 }}>
          <button className="of-back" onClick={onBack}><Icon name="arrow-left" size={15} /> All offerings</button>
          <div className="of-detail-title">
            <span className="of-type-badge"><Icon name={t ? t.icon : "box"} size={13} /> {t ? t.label : offering.type}</span>
            <h1 className="page-title">{offering.name}</h1>
          </div>
          <div className="of-detail-meta"><OfPill status={offering.status} /> {offering.type === "product" && typeof ProdStatusBadge !== "undefined" ? <ProdStatusBadge offering={offering} /> : null} <span>Owner: {offering.owner}</span> <span>· Updated {offering.updated}</span></div>
        </div>
        <div className="ps-head-actions">
          <button className="btn secondary sm" onClick={() => setSpecSheet(true)}><Icon name="file-text" size={14} /> Spec sheet PDF</button>
        </div>
      </div>
      {specSheet && <PsSpecSheet offering={offering} onClose={() => setSpecSheet(false)} />}

      {hasSpec ? (
        <div className="ps-wizard">
          <div className="ps-railnav ps-railnav-top">
            {tabs.map((tb, i) => {
              const idx = tabs.findIndex((x) => x.id === tab);
              return (
                <button key={tb.id} className={`ps-railstep ${tab === tb.id ? "on" : ""} ${i < idx ? "done" : ""}`} onClick={() => setTab(tb.id)}>
                  <span className="ps-railstep-n">{i < idx ? <Icon name="check" size={12} stroke={3} /> : i + 1}</span>
                  <span className="ps-railstep-l"><Icon name={tb.icon} size={14} /> {tb.label}</span>
                </button>
              );
            })}
          </div>
          <div className="ps-wizard-body">
          <div className="ps-wizard-main">
            <div className="card of-detail-card">
              {tab === "overview" && <>{overview}</>}
              {tab === "menu-data" && <PsMenuData offering={offering} />}
              {tab === "details" && <PsDetails offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "processing" && <PsProcessing offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "costing" && <PsCosting offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "pricing" && <PsPricing offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "packaging" && <PsPackaging offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "storage" && <PsStorage offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "manufacturing" && <PsManufacturing offering={offering} canEdit={canEdit} onChange={bump} />}
              {tab === "claims" && <PsClaims offering={offering} />}
              {tab === "gs1" && <PsGs1 offering={offering} setPage={setPage} />}
              {tab === "qr" && <PsQr offering={offering} />}
              {tab === "compliance" && <PsCompliance offering={offering} canEdit={canEdit} setPage={setPage} toast={toast} onChange={bump} onSpecSheet={() => setSpecSheet(true)} />}
              {tab === "pc-summary" && <PcSummary offering={offering} role={role} setPage={setPage} onChange={bump} />}
              {tab === "pc-audit" && <PcAudit offering={offering} />}
              {tab === "documents" && <PsDocuments offering={offering} canEdit={canEdit} onChange={bump} />}
            </div>
            {(() => {
              const idx = tabs.findIndex((tb) => tb.id === tab);
              const prev = idx > 0 ? tabs[idx - 1] : null;
              const next = idx < tabs.length - 1 ? tabs[idx + 1] : null;
              return (
                <div className="ps-stepnav">
                  <button className="btn ghost" disabled={!prev} onClick={() => prev && setTab(prev.id)}>
                    <Icon name="arrow-left" size={15} /> {prev ? prev.label : "Back"}
                  </button>
                  <span className="ps-stepnav-count">Step {idx + 1} of {tabs.length}</span>
                  <button className="btn primary" disabled={false} onClick={() => { if (next) setTab(next.id); else { toast("All steps reviewed"); onBack(); } }}>
                    {next ? next.label : "Done"} <Icon name="arrow-right" size={15} />
                  </button>
                </div>
              );
            })()}
          </div>
          <aside className="ps-railpreview">
            <div className="ps-railnav-h">Live preview</div>
            <div className="ps-preview-card">
              <ProductLivePreview offering={offering} comp={comp} />
            </div>
          </aside>
          </div>
        </div>
      ) : (
        <>
          <div className="of-outputs-strip">{(t ? t.outputs : []).map((o) => <span key={o} className="of-chip ghost"><Icon name="dot" size={12} /> {o}</span>)}</div>
          <div className="card of-detail-card">{overview}</div>
        </>
      )}
    </div>
  );
}

/* Live preview shown in the right rail of the product wizard. */
function ProductLivePreview({ offering, comp }) {
  const sum = (typeof prodComplianceSummary === "function") ? (() => { try { return prodComplianceSummary(offering); } catch (e) { return null; } })() : null;
  const prof = sum && sum.prof;
  const spec = (typeof psGet === "function") ? psGet(offering.id) : { details: {}, packaging: {} };
  const d = spec.details || {}, pk = spec.packaging || {};
  const g = (typeof gs1ForOffering === "function") ? gs1ForOffering(offering.id) : { gtins: [], barcodes: [], qrs: [] };
  const num = (v, u) => prof && prof[v] != null ? (Math.round(prof[v]) + (u || "")) : "—";
  const nrows = [
    ["Calories", num("energy_kcal")], ["Fat", num("fat_g", " g")], ["Saturated", num("fat_saturated_g", " g")],
    ["Carbohydrate", num("carbohydrate_g", " g")], ["Fibre", num("fibre_g", " g")], ["Sugars", num("sugars_g", " g")],
    ["Protein", num("protein_g", " g")], ["Sodium", num("sodium_mg", " mg")], ["Potassium", num("potassium_mg", " mg")],
  ];
  return (
    <div className="ps-prev">
      <div className="ps-prev-badge"><Icon name="package" size={14} /> {offering.name}</div>
      {comp && (
        <div className="ps-prev-ring"><PsRing pct={comp.pct} /><div><b>{comp.pct}% complete</b><span>{comp.missing.length} item(s) outstanding</span></div></div>
      )}

      {/* identity */}
      <div className="ps-prev-meta">
        {d.brandName && <div><span>Brand</span><b>{d.brandName}</b></div>}
        {d.category && <div><span>Category</span><b>{d.category}</b></div>}
        {(d.servingSizeG || prof) && <div><span>Serving</span><b>{d.servingSizeG || (prof && prof.servingG) || "—"} g{d.servingsPerContainer ? ` × ${d.servingsPerContainer}` : ""}</b></div>}
        {pk.packageType && <div><span>Package</span><b>{pk.packageType}</b></div>}
      </div>

      <div className="ps-prev-nft">
        <div className="ps-prev-nft-h">Nutrition Facts {prof ? `· per ${prof.servingG} g` : "(per serving)"}</div>
        {nrows.map(([k, v]) => <div key={k} className="ps-prev-nft-row"><span>{k}</span><b>{v}</b></div>)}
      </div>

      {/* barcodes, all assigned GTINs / batches, live */}
      <div className="ps-prev-sec">
        <div className="ps-prev-sec-h"><Icon name="scan-barcode" size={13} /> Barcodes <span>{g.gtins.length}</span></div>
        {g.gtins.length === 0 && <div className="ps-prev-none">No GTIN assigned yet.</div>}
        {g.gtins.map((gt) => {
          const bc = (g.barcodes || []).find((b) => b.gtinId === gt.id);
          const Barc = window.Barcode;
          return (
            <div key={gt.id} className="ps-prev-bc">
              <div className="ps-prev-bc-top"><span className="pill brand" style={{ fontSize: 9 }}>{(typeof GTIN_TYPES !== "undefined" && GTIN_TYPES[gt.gtinType] || {}).label}</span><span className="gs-mono" style={{ fontSize: 11 }}>{gt.gtin}</span></div>
              {bc && Barc ? <Barc type={bc.barcodeType} value={bc.encodedValue} scale={1.4} height={9} /> : <span className="ps-prev-pending">Barcode pending</span>}
            </div>
          );
        })}
      </div>

      {/* QR codes */}
      {(g.qrs || []).length > 0 && (
        <div className="ps-prev-sec">
          <div className="ps-prev-sec-h"><Icon name="qr-code" size={13} /> QR codes <span>{g.qrs.length}</span></div>
          <div className="ps-prev-qrs">{g.qrs.map((q) => { const QRc = window.QR; return <div key={q.id} className="ps-prev-qr">{QRc ? <QRc value={q.encodedUrl} size={64} /> : null}</div>; })}</div>
        </div>
      )}

      {sum && (
        <div className={`ps-prev-status ${sum.exportReady ? "ok" : "blocked"}`}>
          <Icon name={sum.exportReady ? "shield-check" : "shield-alert"} size={14} />
          {sum.overall}
        </div>
      )}
    </div>
  );
}

/* ───────── Root ───────── */
function OfferingsScreen() {
  const { toast } = useApp();
  const [, bump] = useOfState(0);
  const [creating, setCreating] = useOfState(false);
  const [openId, setOpenId] = useOfState(null);
  const [filter, setFilter] = useOfState(() => window.__ofType || "all");
  const [q, setQ] = useOfState("");
  const [statusF, setStatusF] = useOfState("all");
  const [view, setView] = useOfState(() => window.__ofView || "grid");
  useOfEffect(() => { window.__ofView = view; }, [view]);
  useOfEffect(() => {
    const h = () => bump((n) => n + 1);
    window.addEventListener("nutridms-offerings", h);
    const onType = (e) => { setFilter(e.detail || "all"); setOpenId(null); };
    window.addEventListener("of-filter", onType);
    return () => { window.removeEventListener("nutridms-offerings", h); window.removeEventListener("of-filter", onType); };
  }, []);
  const offerings = (typeof ofLoad === "function") ? ofLoad() : [];
  const types = (typeof OFFERING_TYPES !== "undefined") ? OFFERING_TYPES : [];
  const open = openId ? offerings.find((o) => o.id === openId) : null;

  if (open) return <OfDetail offering={open} onBack={() => setOpenId(null)} />;

  const activeType = types.find((t) => t.id === filter);
  const locked = filter !== "all";          // arrived via a type-specific sidebar entry
  const byType = filter === "all" ? offerings : offerings.filter((o) => o.type === filter);

  // product-status helper (Draft / Review / Approved / Locked / Export Ready)
  const prodStatus = (o) => {
    if (o.type !== "product" || typeof prodComplianceSummary !== "function") return o.status === "published" ? "Published" : "Draft";
    try { return prodComplianceSummary(o).overall; } catch (e) { return "Draft"; }
  };
  const statusBucket = (s) => {
    if (s === "Export Ready" || s === "Locked" || s === "Published") return "ready";
    if (s === "Compliance Approved") return "approved";
    if (s === "Review Required") return "review";
    return "draft";
  };

  const STAT_DEFS = [
    { id: "all", label: locked ? `${activeType.label}s` : "Offerings", icon: activeType ? activeType.icon : "boxes", tone: "brand" },
    { id: "draft", label: "Draft", icon: "file-pen", tone: "neutral" },
    { id: "review", label: "In review", icon: "clock", tone: "warn" },
    { id: "approved", label: "Approved", icon: "stamp", tone: "brand" },
    { id: "ready", label: "Export ready", icon: "check-circle-2", tone: "ok" },
  ];
  const bucketCount = (id) => id === "all" ? byType.length : byType.filter((o) => statusBucket(prodStatus(o)) === id).length;

  const filtered = byType.filter((o) => {
    if (statusF !== "all" && statusBucket(prodStatus(o)) !== statusF) return false;
    if (q && !o.name.toLowerCase().includes(q.toLowerCase())) return false;
    return true;
  });
  const heading = activeType ? activeType.label : "Offerings";
  const sub = activeType
    ? `${activeType.useCase}.`
    : "Compose approved recipes into products, menu items, combos, meal plans, and catering packages.";

  return (
    <div className="page of-page">
      <div className="page-head">
        <div>
          <h1 className="page-title">{heading}</h1>
          <p className="page-sub">{sub}</p>
        </div>
        <button className="btn primary" onClick={() => { window.__ofCreateType = filter === "all" ? null : filter; setCreating(true); }}><Icon name="plus" size={16} /> Create {activeType ? activeType.label : "Offering"}</button>
      </div>

      {/* dashboard stat tiles double as status filters */}
      <div className="of-stats">
        {STAT_DEFS.map((s) => (
          <button key={s.id} className={`of-stat ${s.tone} ${statusF === s.id ? "on" : ""}`} onClick={() => setStatusF(s.id)}>
            <span className="of-stat-ic"><Icon name={s.icon} size={17} /></span>
            <span className="of-stat-v">{bucketCount(s.id)}</span>
            <span className="of-stat-k">{s.label}</span>
          </button>
        ))}
      </div>

      <div className="of-toolbar">
        <div className="of-search"><Icon name="search" size={15} /><input value={q} onChange={(e) => setQ(e.target.value)} placeholder={`Search ${activeType ? activeType.label.toLowerCase() : "offering"}s…`} /></div>
        {!locked && (
          <div className="of-filters inline">
            <button className={`of-filter ${filter === "all" ? "on" : ""}`} onClick={() => setFilter("all")}>All <span className="of-filter-n">{offerings.length}</span></button>
            {types.map((t) => {
              const n = offerings.filter((o) => o.type === t.id).length;
              return <button key={t.id} className={`of-filter ${filter === t.id ? "on" : ""}`} onClick={() => setFilter(t.id)}><Icon name={t.icon} size={13} /> {t.label} <span className="of-filter-n">{n}</span></button>;
            })}
          </div>
        )}
        {(statusF !== "all" || q) && <button className="of-clear" onClick={() => { setStatusF("all"); setQ(""); }}><Icon name="x" size={13} /> Clear</button>}
        <div className="of-viewtog">
          {[["grid", "layout-grid"], ["list", "list"], ["table", "table-2"]].map(([v, ic]) => (
            <button key={v} className={view === v ? "on" : ""} onClick={() => setView(v)} title={v[0].toUpperCase() + v.slice(1) + " view"} aria-label={v + " view"}><Icon name={ic} size={15} /></button>
          ))}
        </div>
      </div>

      {view === "table" ? (
        <div className="of-card-wrap"><table className="of-listtable">
          <thead><tr><th>Name</th><th>Type</th><th>Status</th><th>Recipes</th><th>Owner</th><th>Updated</th></tr></thead>
          <tbody>
            {filtered.map((o) => {
              const t = ofType(o.type);
              const count = t.single ? 1 : (o.components ? o.components.length : (o.days ? o.days.reduce((s, d) => s + (d.meals ? d.meals.length : 0), 0) : 0));
              return (
                <tr key={o.id} onClick={() => setOpenId(o.id)}>
                  <td className="of-lt-nm">{o.name}</td>
                  <td><span className="of-type-badge sm"><Icon name={t.icon} size={12} /> {t.label}</span></td>
                  <td>{o.type === "product" && typeof ProdStatusBadge !== "undefined" ? <ProdStatusBadge offering={o} size="sm" /> : <OfPill status={o.status} />}</td>
                  <td>{count}</td><td>{o.owner}</td><td>{o.updated}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
        {filtered.length === 0 && <div className="of-empty"><div className="icon"><Icon name="boxes" size={26} /></div><h3>Nothing here</h3><p>No items match your filters.</p></div>}
        </div>
      ) : (
      <div className={view === "list" ? "of-list" : "of-grid"}>
        {filtered.map((o) => {
          const t = ofType(o.type);
          const count = t.single ? 1 : (o.components ? o.components.length : (o.days ? o.days.reduce((s, d) => s + (d.meals ? d.meals.length : 0), 0) : 0));
          if (view === "list") {
            return (
              <button key={o.id} className="of-listrow" onClick={() => setOpenId(o.id)}>
                <span className="of-listrow-ic"><Icon name={t.icon} size={17} /></span>
                <span className="of-listrow-main"><b>{o.name}</b><span>{t.label} · {count} {t.single ? "recipe" : o.type === "meal-plan" ? "meals" : "components"}</span></span>
                {o.type === "product" && typeof ProdStatusBadge !== "undefined" ? <ProdStatusBadge offering={o} size="sm" /> : <OfPill status={o.status} />}
                <span className="of-listrow-foot">{o.owner} · {o.updated}</span>
                <Icon name="chevron-right" size={16} className="of-listrow-arrow" />
              </button>
            );
          }
          return (
            <button key={o.id} className="of-card" onClick={() => setOpenId(o.id)}>
              <div className="of-card-top">
                <span className="of-type-badge"><Icon name={t.icon} size={13} /> {t.label}</span>
                {o.type === "product" && typeof ProdStatusBadge !== "undefined" ? <ProdStatusBadge offering={o} size="sm" /> : <OfPill status={o.status} />}
              </div>
              <div className="of-card-nm">{o.name}</div>
              <div className="of-card-meta">
                <span><Icon name="utensils-crossed" size={12} /> {count} {t.single ? "recipe" : o.type === "meal-plan" ? "meals" : "components"}</span>
                {o.type === "catering" && <span><Icon name="users" size={12} /> {o.guestCount} guests</span>}
              </div>
              <div className="of-card-foot"><span>{o.owner}</span><span>{o.updated}</span></div>
            </button>
          );
        })}
        {filtered.length === 0 && (
          <div className="of-empty"><div className="icon"><Icon name="boxes" size={26} /></div><h3>No offerings yet</h3><p>Create your first offering to generate labels, menu data, or group reports.</p></div>
        )}
      </div>
      )}

      {creating && <OfCreatePanel onClose={() => setCreating(false)} onCreate={(o) => { setCreating(false); setOpenId(o.id); toast("Offering created"); }} />}
    </div>
  );
}

Object.assign(window, { OfferingsScreen });

/* ───────── §27 Compliance Dashboard ───────── */
function CdStatusPill({ kind, status }) {
  if (kind === "label") {
    const m = { draft: { label: "Draft", tone: "neutral" }, review: { label: "In Review", tone: "warning" }, approved: { label: "Approved", tone: "success" }, locked: { label: "Locked", tone: "success" } }[status] || { label: status, tone: "neutral" };
    return <span className={`pill ${m.tone}`} style={{ fontSize: 11 }}>{status === "locked" && <Icon name="lock" size={10} stroke={2.6} style={{ marginRight: 3 }} />}{m.label}</span>;
  }
  const m = { pass: { label: "Pass", tone: "success" }, warning: { label: "Warning", tone: "warning" }, fail: { label: "Fail", tone: "error" } }[status] || { label: status, tone: "neutral" };
  return <span className={`pill ${m.tone}`} style={{ fontSize: 11 }}>{m.label}</span>;
}

function ComplianceDashboard() {
  const { toast, role, setPage } = useApp();
  const [, bump] = useOfState(0);
  useOfEffect(() => {
    const h = () => bump((n) => n + 1);
    ["nutridms-offerings", "nutridms-audit", "nutridms-versions"].forEach((e) => window.addEventListener(e, h));
    return () => ["nutridms-offerings", "nutridms-audit", "nutridms-versions"].forEach((e) => window.removeEventListener(e, h));
  }, []);
  const cards = (typeof ofDashboardCards === "function") ? ofDashboardCards() : [];
  const rows = (typeof ofComplianceRows === "function") ? ofComplianceRows() : [];
  const me = (window.currentUser ? (window.currentUser(role) || {}).name : null) || "You";

  const [typeF, setTypeF] = useOfState("all");
  const [statusF, setStatusF] = useOfState("all"); // draft|warning|fail|approved|locked|mine
  const [collapsed, setCollapsed] = useOfState({});
  const types = (typeof OFFERING_TYPES !== "undefined") ? OFFERING_TYPES : [];

  const matchStatus = (r) => {
    if (statusF === "all") return true;
    if (statusF === "mine") return r.reviewer === me;
    if (["draft", "approved", "locked"].includes(statusF)) return r.labelStatus === statusF;
    if (["warning", "fail"].includes(statusF)) return r.compliance === statusF;
    return true;
  };
  const filtered = rows.filter((r) => (typeF === "all" || r.type === typeF) && matchStatus(r));

  const cardClick = (c) => { if (c.filter) { if (c.filter.label) setStatusF(c.filter.label); else if (c.filter.compliance) setStatusF(c.filter.compliance); } };

  const statusLabels = { draft: "Draft", warning: "Warning", fail: "Fail", approved: "Approved", locked: "Locked", mine: "Assigned to me" };
  const chips = [];
  if (typeF !== "all") chips.push({ k: "type", label: "Type: " + (ofType(typeF).label), clear: () => setTypeF("all") });
  if (statusF !== "all") chips.push({ k: "status", label: statusLabels[statusF] || statusF, clear: () => setStatusF("all") });

  // sections shown: all types, or just the active one
  const sectionTypes = typeF === "all" ? types : types.filter((t) => t.id === typeF);
  const addLabel = { product: "Products", "menu-item": "Menu Item", combo: "Combo", "meal-plan": "Menu Plans", catering: "Catering" };

  const Section = ({ t }) => {
    const sRows = rows.filter((r) => r.type === t.id && matchStatus(r));
    const isCollapsed = collapsed[t.id];
    const shown = sRows.slice(0, 2);
    return (
      <div className="cd-sec">
        <div className="cd-sec-head">
          <span className="cd-sec-accent" data-type={t.id} />
          <span className="cd-sec-title">{t.label === "Product" ? "Products" : t.label === "Menu Item" ? "Menu Items" : t.label === "Meal Plan" ? "Menu Plans" : t.label + " Packages"}</span>
          <span className="cd-sec-count">{sRows.length}</span>
          <div className="grow" />
          <button className="btn secondary sm" onClick={() => { window.__ofCreateType = t.id; setPage("offerings"); }}><Icon name="plus" size={14} /> Add {addLabel[t.id] || t.label}</button>
          <button className="cd-sec-toggle" onClick={() => setCollapsed((m) => ({ ...m, [t.id]: !m[t.id] }))}><Icon name={isCollapsed ? "chevron-down" : "chevron-up"} size={16} /></button>
        </div>
        {!isCollapsed && sRows.length > 0 && (
          <div className="cd-table-wrap">
            <table className="cd-table">
              <thead><tr><th>Offering</th><th>Type</th><th>Recipe</th><th>Label Status</th><th>Compliance</th><th>Reviewer</th><th>Last Updated</th><th>Actions</th></tr></thead>
              <tbody>
                {shown.map((r) => (
                  <tr key={r.offering.id}>
                    <td className="cd-of-nm">{r.offering.name}</td>
                    <td><span className="of-type-badge sm" data-type={t.id}><Icon name={t.icon} size={11} /> {t.label}</span></td>
                    <td className="cd-recipe">{r.recipeName}</td>
                    <td><CdStatusPill kind="label" status={r.labelStatus} /></td>
                    <td><CdStatusPill kind="comp" status={r.compliance} /></td>
                    <td className="cd-reviewer"><span className="cd-avatar">{(r.reviewer || "?").split(" ").map((w) => w[0]).slice(0, 2).join("")}</span> {r.reviewer}</td>
                    <td className="cd-updated">{r.updated}</td>
                    <td><button className="cd-viewlabel" onClick={() => { try { window.labelStudioSetEnabled && window.labelStudioSetEnabled(true); } catch (e) {} setPage("label-studio"); }}>View Label</button></td>
                  </tr>
                ))}
              </tbody>
            </table>
            <button className="cd-viewall" onClick={() => { window.__ofType = t.id; setPage("offerings"); }}>View all {sRows.length} {(t.label === "Product" ? "products" : "items")}</button>
          </div>
        )}
        {!isCollapsed && sRows.length === 0 && <div className="cd-sec-empty">No {t.label.toLowerCase()} offerings match these filters.</div>}
      </div>
    );
  };

  return (
    <div className="page of-page cd-page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Compliance Dashboard</h1>
          <p className="page-sub">Label and compliance status across every offering, with live regulatory roll-ups.</p>
        </div>
        <button className="btn secondary" onClick={() => setPage("offerings")}><Icon name="boxes" size={16} /> Offerings</button>
      </div>

      <div className="cd-cards">
        {cards.map((c) => (
          <button key={c.id} className={`cd-card ${c.tone} ${c.filter ? "clickable" : ""}`} onClick={() => cardClick(c)}>
            <div className="cd-card-ic"><Icon name={c.icon} size={17} /></div>
            <div className="cd-card-v">{c.value}{c.hint ? <span className="cd-card-hint">{c.hint}</span> : null}</div>
            <div className="cd-card-l">{c.label}</div>
          </button>
        ))}
      </div>

      <div className="cd-layout">
        <aside className="cd-sidemenu">
          <button className={`cd-sidebtn ${typeF === "all" ? "on" : ""}`} onClick={() => setTypeF("all")}><Icon name="layout-grid" size={15} /> All types</button>
          {types.map((t) => <button key={t.id} className={`cd-sidebtn ${typeF === t.id ? "on" : ""}`} onClick={() => setTypeF(t.id)}><Icon name={t.icon || "package"} size={15} /> {t.label}</button>)}
          <div className="cd-sidemenu-sep" />
          <button className="cd-sidebtn ghost" onClick={() => window.__toast && window.__toast("Advanced filter")}><Icon name="sliders-horizontal" size={15} /> Advanced Filter</button>
        </aside>
        <div className="cd-main">
          {chips.length > 0 && (
            <div className="cd-applied">
              <span className="cd-applied-lbl">Applied Filters:</span>
              {chips.map((c) => <span key={c.k} className="cd-chip">{c.label}<button onClick={c.clear}><Icon name="x" size={11} /></button></span>)}
              <button className="cd-clear" onClick={() => { setTypeF("all"); setStatusF("all"); }}>Clear all</button>
            </div>
          )}
          {sectionTypes.map((t) => <Section key={t.id} t={t} />)}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ComplianceDashboard });
