function PrepRecipes() {
  const { L, lang, fmt, O, inv, setInv, invMap, recipes, ops, upd, go, toast } = useMizo();
  const [sel, setSel] = React.useState(O.prep[0].id);
  const [mult, setMult] = React.useState(1);
  const p = O.prep.find((x) => x.id === sel);
  const rn = Object.fromEntries(recipes.map((r) => [r.id, r]));
  const uL = { kg: 'kg', L: 'L', portions: L('portions', 'portions'), pieces: L('pieces', 'morceaux') };
  const cost = (x) => x.lines.reduce((s, [ing, q]) => s + invMap[ing].cost * q, 0);
  const lines = p.lines.map(([ing, q]) => ({ i: invMap[ing], q: q * mult }));
  const short = lines.filter((l) => l.i.onHand < l.q);
  const make = () => {
    setInv(inv.map((i) => { const l = lines.find((x) => x.i.id === i.id); return l ? { ...i, onHand: Math.max(0, Math.round((i.onHand - l.q) * 100) / 100) } : i; }));
    upd('lots', (ls) => [...ls, { id: 'L' + (Date.now() % 100000), ing: null, prep: p.id, qty: p.yieldQty * mult, unit: p.unit, loc: 'walkin', recv: TODAY, exp: addDays(TODAY, p.shelf) }]);
    toast(L(`Batch logged · ingredients taken from stock · use by ${fmt.date(addDays(TODAY, p.shelf))}`, `Lot noté · ingrédients retirés du stock · à utiliser avant le ${fmt.date(addDays(TODAY, p.shelf))}`));
  };
  return (
    <div className="page">
      <PageHead sub={L('Sauces, marinades and batches you make ahead — what they cost, how much they make, and which dishes use them.', 'Sauces, marinades et lots préparés à l’avance — coût, rendement et plats qui les utilisent.')} />
      <section className="recipes">
        <div className="panel panel-flush rlist">
          <ul style={{ paddingTop: '.5rem' }}>{O.prep.map((x) => <li key={x.id}><button className={'rlist-item' + (x.id === sel ? ' on' : '')} onClick={() => { setSel(x.id); setMult(1); }}><span className="rlist-main">{x.name[lang]}<span className="muted sm">{fmt.num(x.yieldQty)} {uL[x.unit]} · {fmt.money(cost(x))}</span></span><span className="tnum muted sm">{fmt.money(cost(x) / x.yieldQty)}/{x.unit === 'portions' ? L('ptn', 'ptn') : x.unit === 'pieces' ? L('pc', 'mcx') : x.unit}</span></button></li>)}</ul>
        </div>
        <div className="panel">
          <div className="red-head"><div><div className="card-kicker">{L('Prep recipe', 'Recette de préparation')}</div><h2>{p.name[lang]}</h2></div>
            <div className="field"><label>{L('Batch size', 'Taille du lot')}</label><Seg size="sm" value={mult} onChange={setMult} options={[[0.5, '½×'], [1, '1×'], [2, '2×'], [3, '3×']]} /></div></div>
          <div className="red-stats">
            <Stat label={L('Makes', 'Donne')} value={`${fmt.num(p.yieldQty * mult)} ${uL[p.unit]}`} />
            <Stat label={L('Batch cost', 'Coût du lot')} value={fmt.money(cost(p) * mult)} />
            <Stat label={L('Cost per unit', 'Coût par unité')} value={fmt.money(cost(p) / p.yieldQty)} tone="acc">/{uL[p.unit]}</Stat>
            <Stat label={L('Keeps', 'Se conserve')} value={`${p.shelf} ${L('days', 'jours')}`}>{p.time} min {L('to make', 'de préparation')}</Stat>
          </div>
          <div className="table-scroll">
            <table className="table mtable reditor">
              <thead><tr><th>{L('Ingredient', 'Ingrédient')}</th><th className="num">{L('Quantity', 'Quantité')}</th><th className="num hide-sm">{L('In stock', 'En stock')}</th><th className="num">{L('Cost', 'Coût')}</th></tr></thead>
              <tbody>{lines.map(({ i, q }) => <tr key={i.id}><td className="cell-main">{i.name[lang]}</td><td className="num tnum">{fmt.num(Math.round(q * 1000) / 1000)} <span className="muted">{i.unit}</span></td><td className={'num tnum hide-sm' + (i.onHand < q ? ' txt-neg' : '')}>{fmt.num(i.onHand)}</td><td className="num tnum">{fmt.money(i.cost * q)}</td></tr>)}</tbody>
            </table>
          </div>
          <p className="muted" style={{ margin: 0 }}><Icon n="note" /> {p.steps[lang]}</p>
          <div><div className="dr-label">{L('Used in', 'Utilisé dans')}</div><div className="chips" style={{ marginTop: '.4rem' }}>{p.used.map((id) => <button key={id} className="chip" onClick={() => go('menu', { recipe: id })}>{rn[id].name[lang]}</button>)}</div></div>
          <div className="dr-row" style={{ flexWrap: 'wrap' }}>
            <span className="muted sm">{short.length ? <span className="txt-neg">{L('Not enough', 'Pas assez de')} {short.map((l) => l.i.name[lang]).join(', ')}</span> : L('Logging a batch takes the ingredients out of stock and adds a dated lot to Expiry.', 'Noter un lot retire les ingrédients du stock et ajoute un lot daté.')}</span>
            <button className="btn btn-primary" disabled={short.length > 0} onClick={make}><Icon n="cooking-pot" />{L('Log batch made', 'Noter le lot préparé')}</button>
          </div>
        </div>
      </section>
    </div>
  );
}

function Yields() {
  const { L, lang, fmt, inv, invMap, ops, upd, toast } = useMizo();
  const [t, setT] = React.useState({ ing: 'pork', raw: '', out: '' });
  const rows = inv.filter((i) => (ops.meta[i.id] || [])[5] < 100).map((i) => { const y = ops.meta[i.id][5]; return { i, y, real: i.cost / (y / 100) }; }).sort((a, b) => a.y - b.y);
  const pct = Number(t.raw) > 0 && Number(t.out) > 0 ? (Number(t.out) / Number(t.raw)) * 100 : null;
  const save = () => { upd('meta', (m) => ({ ...m, [t.ing]: m[t.ing].map((v, k) => (k === 5 ? Math.round(pct) : v)) })); toast(L(`Yield for ${invMap[t.ing].name.en} set to ${Math.round(pct)}%`, `Rendement de ${invMap[t.ing].name.fr} : ${Math.round(pct)} %`)); setT({ ...t, raw: '', out: '' }); };
  return (
    <div className="page">
      <PageHead sub={L('A kilo of pork shoulder isn’t a kilo on the plate. Yield is what’s left after trimming, peeling and cooking — and it changes the real cost.', 'Un kilo d’épaule de porc ne fait pas un kilo dans l’assiette. Le rendement, c’est ce qui reste après parage et cuisson.')} />
      <section className="grid-2-1">
        <div className="panel panel-flush">
          <div className="table-scroll">
            <table className="table mtable">
              <thead><tr><th>{L('Ingredient', 'Ingrédient')}</th><th className="num">{L('You pay', 'Prix payé')}</th><th>{L('Yield', 'Rendement')}</th><th className="num">{L('Real cost of what you serve', 'Coût réel servi')}</th></tr></thead>
              <tbody>{rows.map(({ i, y, real }) => (
                <tr key={i.id}><td className="cell-main">{i.name[lang]}</td><td className="num tnum">{fmt.money(i.cost)}<div className="cell-sub">/ {i.unit}</div></td>
                  <td><div className="mixbar"><div className="hbar-track"><div className="hbar-fill" style={{ width: y + '%' }}></div></div><span className="tnum">{y}%</span></div></td>
                  <td className="num"><span className="tnum">{fmt.money(real)}</span><div className="cell-sub txt-neg">+{fmt.money(real - i.cost)}</div></td></tr>
              ))}</tbody>
            </table>
          </div>
        </div>
        <div className="panel">
          <h3>{L('Run a yield test', 'Faire un test de rendement')}</h3>
          <p className="muted sm" style={{ margin: 0 }}>{L('Weigh it before, prep or cook it, weigh what’s usable.', 'Pesez avant, préparez ou cuisez, pesez ce qui est utilisable.')}</p>
          <div className="field"><label>{L('Ingredient', 'Ingrédient')}</label><select className="input" value={t.ing} onChange={(e) => setT({ ...t, ing: e.target.value })}>{rows.map(({ i }) => <option key={i.id} value={i.id}>{i.name[lang]}</option>)}</select></div>
          <div className="form-grid">
            <div className="field"><label>{L('Raw weight', 'Poids brut')} ({invMap[t.ing].unit})</label><input className="input" type="number" step="0.01" value={t.raw} onChange={(e) => setT({ ...t, raw: e.target.value })} /></div>
            <div className="field"><label>{L('Usable weight', 'Poids utilisable')} ({invMap[t.ing].unit})</label><input className="input" type="number" step="0.01" value={t.out} onChange={(e) => setT({ ...t, out: e.target.value })} /></div>
          </div>
          <div className="dr-row"><span className="muted">{L('Result', 'Résultat')}</span><b className="big tnum">{pct ? fmt.pct(pct) : '—'}</b></div>
          <button className="btn btn-primary" disabled={!pct || pct > 100} onClick={save} style={{ alignSelf: 'flex-start' }}><Icon n="floppy-disk" />{L('Save yield', 'Enregistrer')}</button>
        </div>
      </section>
    </div>
  );
}

function Substitutions() {
  const { L, lang, fmt, O, inv, invMap, recipes, ops, upd, target, toast } = useMizo();
  const [sel, setSel] = React.useState(ops.subs[0].id);
  const [add, setAdd] = React.useState(null);
  const s = ops.subs.find((x) => x.id === sel);
  const rows = recipes.filter((r) => r.lines.some((l) => l.ing === s.from)).map((r) => { const c = recipeCost(r, invMap); const q = r.lines.filter((l) => l.ing === s.from).reduce((a, l) => a + l.qty, 0); const nt = c.total + q * (s.cost - invMap[s.from].cost); return { r, c, q, nt, nfc: (nt / r.price) * 100, dm: (c.total - nt) * r.sold }; });
  const tot = rows.reduce((a, x) => a + x.dm, 0);
  const alName = s.removes ? O.allergens.find((a) => a[0] === s.removes)[1][lang] : null;
  return (
    <div className="page">
      <PageHead sub={L('Approved swaps for when something is out, too expensive, or a guest needs it — and what each swap does to cost and allergens.', 'Substitutions approuvées en cas de rupture, de prix élevé ou de besoin d’un client — et leur effet sur le coût et les allergènes.')}>
        <button className="btn btn-primary" onClick={() => setAdd({ from: 'feta', name: '', cost: '' })}><Icon n="plus" />{L('Add substitute', 'Ajouter')}</button>
      </PageHead>
      <section className="grid-1-2">
        <div className="panel panel-flush">
          <ul className="opps" style={{ paddingTop: '.5rem' }}>{ops.subs.map((x) => <li key={x.id}><button className={'opp' + (x.id === sel ? ' on' : '')} onClick={() => setSel(x.id)}><span className="rlist-main">{x.name[lang]}<span className="muted sm">{L('instead of', 'au lieu de')} {invMap[x.from].name[lang]}</span></span>{x.approved ? <Pill tone="pos">{L('Approved', 'Approuvé')}</Pill> : <Pill tone="neutral">{L('Idea', 'Idée')}</Pill>}</button></li>)}</ul>
        </div>
        <div className="panel">
          <div className="panel-head"><div><div className="card-kicker">{invMap[s.from].name[lang]} → </div><h3>{s.name[lang]}</h3><p className="muted">{s.note[lang]}</p></div>
            <div className="dr-row" style={{ gap: '.6rem' }}><span className="muted sm">{L('Approved for the kitchen', 'Approuvé pour la cuisine')}</span><Toggle on={!!s.approved} label={L('Approved', 'Approuvé')} onChange={(v) => upd('subs', (ss) => ss.map((x) => (x.id === s.id ? { ...x, approved: v } : x)))} /></div></div>
          <section className="stats">
            <Stat label={L('Price', 'Prix')} value={fmt.money(s.cost)}>{L('vs', 'vs')} {fmt.money(invMap[s.from].cost)} / {invMap[s.from].unit}</Stat>
            <Stat label={L('Profit change if used everywhere', 'Effet sur le profit si utilisé partout')} value={(tot >= 0 ? '+' : '−') + fmt.money0(Math.abs(tot))} tone={tot >= 0 ? 'pos' : 'neg'}>{L('per month', 'par mois')}</Stat>
            <Stat label={L('Allergens', 'Allergènes')} value={alName ? L('Removes', 'Retire') + ' ' + alName.toLowerCase() : L('No change', 'Aucun changement')} tone={alName ? 'acc' : ''} />
          </section>
          <div className="table-scroll">
            <table className="table mtable reditor">
              <thead><tr><th>{L('Dish', 'Plat')}</th><th className="num">{L('Plate cost', 'Coût')}</th><th className="num">{L('Food cost', 'Coût %')}</th><th className="num">{L('Per month', 'Par mois')}</th></tr></thead>
              <tbody>{rows.map((x) => <tr key={x.r.id}><td className="cell-main">{x.r.name[lang]}</td><td className="num tnum">{fmt.money(x.c.total)} → {fmt.money(x.nt)}</td><td className="num"><Pill tone={fcTone(x.c.fc, target)}>{fmt.pct(x.c.fc)}</Pill> → <Pill tone={fcTone(x.nfc, target)}>{fmt.pct(x.nfc)}</Pill></td><td className={'num tnum ' + (x.dm >= 0 ? 'txt-pos' : 'txt-neg')}>{x.dm >= 0 ? '+' : '−'}{fmt.money0(Math.abs(x.dm))}</td></tr>)}</tbody>
            </table>
          </div>
          <span className="muted sm">{L('This is a simulation — recipe costs don’t change until you switch the ingredient’s supplier or price.', 'Simulation — les coûts ne changent pas tant que le fournisseur ou le prix de l’ingrédient ne change pas.')}</span>
        </div>
      </section>
      <Modal open={!!add} onClose={() => setAdd(null)} title={L('Add a substitute', 'Ajouter une substitution')} actions={<><button className="btn btn-secondary" onClick={() => setAdd(null)}>{L('Cancel', 'Annuler')}</button><button className="btn btn-primary" disabled={!add || !add.name.trim() || !Number(add.cost)} onClick={() => { const id = 'sub' + Date.now(); upd('subs', (ss) => [...ss, { id, from: add.from, name: { en: add.name, fr: add.name }, cost: Number(add.cost), note: { en: '', fr: '' } }]); setSel(id); setAdd(null); toast(L('Substitute added', 'Substitution ajoutée')); }}>{L('Add', 'Ajouter')}</button></>}>
        {add ? <div className="form-grid">
          <div className="field span-2"><label>{L('Replaces', 'Remplace')}</label><select className="input" value={add.from} onChange={(e) => setAdd({ ...add, from: e.target.value })}>{inv.map((i) => <option key={i.id} value={i.id}>{i.name[lang]}</option>)}</select></div>
          <div className="field"><label>{L('Substitute product', 'Produit de remplacement')}</label><input className="input" value={add.name} onChange={(e) => setAdd({ ...add, name: e.target.value })} /></div>
          <div className="field"><label>{L('Price per', 'Prix par')} {invMap[add.from].unit} (CAD)</label><input className="input" type="number" step="0.01" value={add.cost} onChange={(e) => setAdd({ ...add, cost: e.target.value })} /></div>
        </div> : null}
      </Modal>
    </div>
  );
}

function Allergens() {
  const { L, lang, O, recipes, ops } = useMizo();
  const [safe, setSafe] = React.useState('');
  const of = (r) => [...new Set(r.lines.flatMap((l) => (ops.meta[l.ing] || [])[4] || []))];
  const cols = O.allergens.filter(([k]) => recipes.some((r) => of(r).includes(k)));
  const subFor = (r, a) => ops.subs.find((s) => s.approved && s.removes === a && r.lines.some((l) => l.ing === s.from));
  return (
    <div className="page">
      <PageHead sub={L('Built from each ingredient’s allergens, so it updates when a recipe changes. Always confirm with the kitchen for severe allergies.', 'Construit à partir des allergènes des ingrédients; se met à jour avec les recettes. Confirmez toujours avec la cuisine pour les allergies graves.')}>
        <select className="input" style={{ maxWidth: 240 }} value={safe} onChange={(e) => setSafe(e.target.value)}><option value="">{L('Show dishes safe for…', 'Plats sans…')}</option>{cols.map(([k, n]) => <option key={k} value={k}>{L('No', 'Sans')} {n[lang].toLowerCase()}</option>)}</select>
        <button className="btn btn-secondary" onClick={() => window.print()}><Icon n="printer" />{L('Print allergen sheet', 'Imprimer la fiche')}</button>
      </PageHead>
      <div className="panel panel-flush">
        <div className="table-scroll">
          <table className="table mtable perm">
            <thead><tr><th>{L('Dish', 'Plat')}</th>{cols.map(([k, n]) => <th key={k} className="num">{n[lang]}</th>)}</tr></thead>
            <tbody>{recipes.map((r) => { const a = of(r); const ok = safe && !a.includes(safe); const fix = safe && a.includes(safe) && subFor(r, safe); return (
              <tr key={r.id} className={safe && !ok && !fix ? 'row-soft' : ''}>
                <td><div className="cell-main">{r.name[lang]} {ok ? <Pill tone="pos">{L('Safe', 'Sans')}</Pill> : fix ? <Pill tone="warn">{L('With swap', 'Avec substitution')}</Pill> : null}</div>{fix ? <div className="cell-sub">{fix.name[lang]}</div> : null}</td>
                {cols.map(([k]) => <td key={k} className="num">{a.includes(k) ? <span className="al-dot" title={k}></span> : <span className="perm-none">·</span>}</td>)}
              </tr>
            ); })}</tbody>
          </table>
        </div>
      </div>
      <div className="suggest"><Icon n="warning" /><div>{L('Fries and pita share the fryer and grill — cross-contact is possible. Edit allergens in Inventory → Ingredients.', 'Frites et pitas partagent la friteuse et le grill — contact croisé possible. Modifiez les allergènes dans Inventaire → Ingrédients.')}</div></div>
    </div>
  );
}

function PriceSim() {
  const { L, lang, fmt, recipes, setRecipes, invMap, target, toast } = useMizo();
  const [pct, setPct] = React.useState(5);
  const [sens, setSens] = React.useState('med');
  const [over, setOver] = React.useState({});
  const e = { low: -0.3, med: -0.8, high: -1.5 }[sens];
  const r95 = (p) => Math.max(0.95, Math.round(p + 0.05) - 0.05);
  const rows = recipes.map((r) => { const c = recipeCost(r, invMap); const np = over[r.id] != null && over[r.id] !== '' ? Number(over[r.id]) : r95(r.price * (1 + pct / 100)); const ch = (np - r.price) / r.price; const ns = Math.max(0, Math.round(r.sold * (1 + e * ch))); return { r, c, np, ns, now: c.margin * r.sold, then: (np - c.total) * ns, nfc: (c.total / np) * 100 }; });
  const N = rows.reduce((s, x) => s + x.now, 0), M = rows.reduce((s, x) => s + x.then, 0);
  const apply = () => { setRecipes(recipes.map((r) => ({ ...r, price: rows.find((x) => x.r.id === r.id).np }))); setOver({}); setPct(0); toast(L('New menu prices applied to recipes', 'Nouveaux prix appliqués aux recettes')); };
  return (
    <div className="page">
      <PageHead sub={L('Try a price change before you print new menus. MIZO estimates how many fewer plates you might sell, and what you’d keep.', 'Essayez un changement de prix avant d’imprimer les menus. MIZO estime la baisse des ventes et ce que vous garderiez.')}>
        <button className="btn btn-primary" onClick={apply}><Icon n="check-circle" />{L('Apply these prices', 'Appliquer ces prix')}</button>
      </PageHead>
      <SeeAlso k="priceSim" />
      <section className="grid-1-2">
        <div className="panel">
          <div className="set-row col"><div className="dr-row"><div>{L('Change all prices by', 'Changer tous les prix de')}</div><b className="big tnum">{pct > 0 ? '+' : ''}{pct}%</b></div><input type="range" className="range" min="-10" max="15" value={pct} onChange={(ev) => { setPct(Number(ev.target.value)); setOver({}); }} /></div>
          <div className="set-row col"><div>{L('How much will guests react?', 'Réaction des clients?')}</div><Seg size="sm" value={sens} onChange={setSens} options={[['low', L('Barely', 'Peu')], ['med', L('Somewhat', 'Un peu')], ['high', L('A lot', 'Beaucoup')]]} /><span className="muted sm">{L('Regulars and lunch crowds usually react “somewhat”.', 'Les habitués réagissent généralement « un peu ».')}</span></div>
          <section className="stats">
            <Stat label={L('Profit today', 'Profit actuel')} value={fmt.money0(N)}>{L('per month', 'par mois')}</Stat>
            <Stat label={L('After change', 'Après changement')} value={fmt.money0(M)} tone={M >= N ? 'pos' : 'neg'}>{M >= N ? '+' : '−'}{fmt.money0(Math.abs(M - N))}</Stat>
          </section>
          <span className="muted sm">{L('Prices round to .95. An estimate, not a promise — test on a few dishes first.', 'Prix arrondis à ,95. Une estimation — testez d’abord sur quelques plats.')}</span>
        </div>
        <div className="panel panel-flush">
          <div className="table-scroll">
            <table className="table mtable">
              <thead><tr><th>{L('Dish', 'Plat')}</th><th className="num">{L('Now', 'Actuel')}</th><th>{L('New price', 'Nouveau prix')}</th><th className="num hide-sm">{L('Sold / mo', 'Vendus / mois')}</th><th className="num">{L('Food cost', 'Coût')}</th><th className="num">{L('Profit / mo', 'Profit / mois')}</th></tr></thead>
              <tbody>{rows.map((x) => (
                <tr key={x.r.id}><td className="cell-main">{x.r.name[lang]}</td><td className="num tnum">{fmt.money(x.r.price)}</td>
                  <td><div className="money-input sm-money"><span>$</span><input className="input" type="number" step="0.05" value={over[x.r.id] ?? x.np.toFixed(2)} onChange={(ev) => setOver({ ...over, [x.r.id]: ev.target.value })} /></div></td>
                  <td className="num tnum hide-sm">{fmt.num(x.r.sold)} → {fmt.num(x.ns)}</td><td className="num"><Pill tone={fcTone(x.nfc, target)}>{fmt.pct(x.nfc)}</Pill></td>
                  <td className="num"><span className="tnum">{fmt.money0(x.then)}</span><div className={'cell-sub ' + (x.then >= x.now ? 'txt-pos' : 'txt-neg')}>{x.then >= x.now ? '+' : '−'}{fmt.money0(Math.abs(x.then - x.now))}</div></td></tr>
              ))}</tbody>
            </table>
          </div>
        </div>
      </section>
    </div>
  );
}

Object.assign(window, { PrepRecipes, Yields, Substitutions, Allergens, PriceSim });
