const FK = ['rev', 'fb', 'pack', 'lab', 'rent', 'util', 'other', 'tk'];
const fsum = (rows) => rows.reduce((a, x) => { FK.forEach((k) => { a[k] += x[k] != null ? x[k] : k === 'tk' ? x.rev / 25.65 : 0; }); a.days += x.days || 1; return a; }, Object.fromEntries([...FK, 'days'].map((k) => [k, 0])));
function finK(a) {
  const F = window.MIZO_FIN;
  const cogs = a.fb + a.pack, opx = a.rent + a.util + a.other, bevRev = a.rev * F.BS, foodRev = a.rev - bevRev, bevCogs = bevRev * F.BC, foodCogs = a.fb - bevCogs, gross = a.rev - cogs, op = gross - a.lab - opx;
  return { ...a, cogs, opx, bevRev, foodRev, bevCogs, foodCogs, gross, op, prime: cogs + a.lab, grossPct: (gross / a.rev) * 100, opPct: (op / a.rev) * 100, foodPct: (foodCogs / foodRev) * 100, bevPct: (bevCogs / bevRev) * 100, labPct: (a.lab / a.rev) * 100, primePct: ((cogs + a.lab) / a.rev) * 100, cogsPct: (cogs / a.rev) * 100, opxPct: (opx / a.rev) * 100, avgTk: a.rev / a.tk };
}
// scale day rows by the per-day rate ratio of a reference month (last year or budget) to the actual month
const finScale = (rows, ref, base) => { const s = fsum(rows); const o = { ...s }; FK.forEach((k) => { if (base[k]) o[k] = s[k] * ((ref[k] != null ? ref[k] : ref.rev / 25.65) / ref.days) / ((base[k] != null ? base[k] : base.rev / 25.65) / base.days); }); if (!base.tk) o.tk = s.tk * (ref.rev / ref.days) / (base.rev / base.days); return o; };
const FIN_PERIODS = [['today', 'Today', 'Aujourd’hui'], ['week', 'This week', 'Cette semaine'], ['month', 'This month', 'Ce mois-ci'], ['last', 'Last month', 'Mois dernier'], ['12m', 'Last 12 months', '12 derniers mois']];
const FIN_CMPS = [['prev', 'vs previous period', 'vs période précédente'], ['py', 'vs same period last year', 'vs l’an dernier'], ['bud', 'vs budget', 'vs budget']];
function finPeriod(p, c, L) {
  const F = window.MIZO_FIN, d = F.days, oc = F.months[11], sp = F.months[10];
  const rng = (a, b) => d.filter((x) => x.d >= a && x.d <= b);
  const sumM = (arr, proOct) => fsum(arr.map((m) => (proOct && m.k === '2026-10' && m.days === 31 ? Object.fromEntries(Object.entries(m).map(([k, v]) => [k, typeof v === 'number' && k !== 'days' && k !== 'full' && k !== 'g' ? (v * 28) / 31 : v])) : m)).map((m) => ({ ...m, days: m.days })));
  const def = {
    today: { rows: rng('2026-10-28', '2026-10-28'), prev: rng('2026-10-21', '2026-10-21'), base: oc, i: 11, lab: L('Wed, Oct 28 · so far', 'mer. 28 oct. · jusqu’ici'), prevLab: L('last Wednesday', 'mercredi dernier') },
    week: { rows: rng('2026-10-26', '2026-10-28'), prev: rng('2026-10-19', '2026-10-21'), base: oc, i: 11, lab: L('Mon Oct 26 – today', 'lun. 26 oct. – aujourd’hui'), prevLab: L('same days last week', 'mêmes jours la semaine dernière') },
    month: { rows: rng('2026-10-01', '2026-10-28'), prev: rng('2026-09-01', '2026-09-28'), base: oc, i: 11, lab: L('Oct 1–28', '1–28 oct.'), prevLab: L('Sep 1–28', '1–28 sept.') },
  }[p];
  let cur, cmp, cmpLab;
  if (def) {
    cur = fsum(def.rows);
    if (c === 'prev') { cmp = fsum(def.prev); cmpLab = def.prevLab; }
    else if (c === 'py') { cmp = finScale(def.rows, F.py[def.i], def.base); cmpLab = L('same days, 2025', 'mêmes jours, 2025'); }
    else { cmp = finScale(def.rows, F.budget[def.i], def.base); cmpLab = L('budget', 'budget'); }
    return { cur: finK(cur), cmp: finK(cmp), lab: def.lab, cmpLab, rows: def.rows, closed: false, partial: p === 'today' };
  }
  if (p === 'last') { cur = fsum([sp]); cmp = c === 'prev' ? fsum([F.months[9]]) : c === 'py' ? fsum([F.py[10]]) : fsum([F.budget[10]]); return { cur: finK(cur), cmp: finK(cmp), lab: L('September 2026', 'Septembre 2026'), cmpLab: c === 'prev' ? L('August', 'août') : c === 'py' ? L('September 2025', 'septembre 2025') : L('budget', 'budget'), rows: d.filter((x) => x.d < '2026-10-01'), closed: true }; }
  cur = sumM(F.months); cmp = c === 'bud' ? sumM(F.budget, true) : sumM(F.py);
  return { cur: finK(cur), cmp: finK(cmp), lab: L('Nov 2025 – Oct 28, 2026', 'nov. 2025 – 28 oct. 2026'), cmpLab: c === 'bud' ? L('budget', 'budget') : L('prior 12 months', '12 mois précédents'), rows: null, closed: false };
}

function Prov({ k, note, short }) {
  const { L } = useMizo();
  const m = { v: ['seal-check', L('Verified', 'Vérifié'), 'pos'], e: ['approximate-equals', L('Estimated', 'Estimé'), 'warn'], m: ['question', L('Missing', 'Manquant'), 'neg'] }[k];
  if (!m) return null;
  return <span className={'prov prov-' + m[2] + (short ? ' short' : '')} title={note || m[1]}><Icon n={m[0]} />{short ? null : m[1]}</span>;
}

function ProvLegend() {
  const { L } = useMizo();
  return (
    <div className="prov-legend">
      <span className="tag tag-outline"><Icon n="flask" />{L('Demo financials — no accounting or POS system connected', 'Données de démonstration — aucun système comptable ni PDV connecté')}</span>
      <span><Prov k="v" /> {L('matched to invoices, payroll or bank', 'concorde avec factures, paie ou banque')}</span>
      <span><Prov k="e" /> {L('modelled by MIZO', 'modélisé par MIZO')}</span>
      <span><Prov k="m" /> {L('not entered yet', 'pas encore saisi')}</span>
    </div>
  );
}

function FinPicker() {
  const { L, fin, setFin } = useMizo();
  const P = finPeriod(fin.p, fin.c, L);
  return (
    <div className="fin-picker">
      <span className="fin-range"><Icon n="calendar-blank" />{P.lab}<span className="muted">· {L('compared with', 'comparé à')} {P.cmpLab}</span></span>
      <Seg size="sm" value={fin.p} onChange={(v) => setFin({ ...fin, p: v })} options={FIN_PERIODS.map(([k, en, fr]) => [k, L(en, fr)])} />
      <label className="sr-only" htmlFor="fin-cmp">{L('Compare with', 'Comparer avec')}</label><select id="fin-cmp" className="input" value={fin.c} onChange={(e) => setFin({ ...fin, c: e.target.value })} aria-label={L('Compare with', 'Comparer avec')}>{FIN_CMPS.map(([k, en, fr]) => <option key={k} value={k}>{L(en, fr)}</option>)}</select>
    </div>
  );
}

function Pts({ v, invert }) {
  const { lang } = useMizo();
  const good = invert ? v < 0 : v > 0, n = Math.abs(v).toFixed(1).replace('.', lang === 'fr' ? ',' : '.');
  return <span className={'delta ' + (Math.abs(v) < 0.05 ? 'flat' : good ? 'pos' : 'neg')}><Icon n={v > 0 ? 'arrow-up-right' : v < 0 ? 'arrow-down-right' : 'minus'} />{n} {lang === 'fr' ? 'pts' : 'pts'}</span>;
}

function Metric({ ic, label, value, delta, cmpLab, prov, provNote, onClick, hero, sub }) {
  return (
    <button className={'kpi metric' + (hero ? ' kpi-hero' : '')} onClick={onClick}>
      <div className="kpi-label">{ic ? <Icon n={ic} /> : null}{label}<Prov k={prov} note={provNote} short /></div>
      <div className="kpi-value">{value}</div>
      <div className="kpi-foot">{delta}{cmpLab ? <span>{cmpLab}</span> : null}{sub ? <span>{sub}</span> : null}</div>
      <Icon n="calculator" className="metric-ic" />
    </button>
  );
}

function CalcView({ d }) {
  const { L, calc, go } = useMizo();
  return (
    <div className="dr">
      <div className="dr-head"><div><div className="card-kicker">{L('How this number is built', 'Comment ce chiffre est calculé')}</div><h2>{d.title}</h2></div><button className="btn btn-icon btn-secondary" onClick={() => calc(null)} aria-label="Close"><Icon n="x" /></button></div>
      <div className="dr-sec">
        <div className="dr-row"><b className="calc-big tnum">{d.value}</b><Prov k={d.prov} note={d.provNote} /></div>
        {d.period ? <span className="muted sm">{d.period}</span> : null}
        {d.formula ? <div className="calc-formula">{d.formula}</div> : null}
      </div>
      {d.inputs ? <div className="dr-sec">
        <div className="dr-label">{L('Inputs', 'Données')}</div>
        {d.inputs.map((x, i) => <div key={i} className={'ln calc-ln' + (x.tot ? ' tot' : '')}><span><span className="calc-op">{x.op || ''}</span>{x.label}</span><span className="calc-v"><b>{x.v}</b>{x.prov ? <Prov k={x.prov} note={x.note} short /> : null}</span></div>)}
      </div> : null}
      {d.cmp ? <div className="dr-sec"><div className="dr-label">{L('Compared with', 'Comparé à')} {d.cmp.lab}</div><div className="dr-row"><b className="tnum">{d.cmp.v}</b>{d.cmp.delta}</div></div> : null}
      {d.rows ? <div className="dr-sec">
        <div className="dr-label">{d.rowsTitle || L('Supporting data', 'Données de soutien')}</div>
        <div className="table-scroll"><table className="table mtable calc-table"><thead><tr>{d.rows.head.map((h, i) => <th key={i} className={i ? 'num' : ''}>{h}</th>)}</tr></thead><tbody>{d.rows.body.map((r, i) => <tr key={i}>{r.map((c, j) => <td key={j} className={j ? 'num tnum' : ''}>{c}</td>)}</tr>)}</tbody></table></div>
      </div> : null}
      {d.notes && d.notes.length ? <div className="dr-sec">{d.notes.map((n, i) => <p key={i} className="muted sm" style={{ margin: 0 }}><Icon n="info" /> {n}</p>)}</div> : null}
      {d.to ? <div className="dr-sec"><button className="btn btn-secondary" onClick={() => { calc(null); go(d.to[0], { tab: d.to[1] }); }}>{d.toLabel || L('Open the full report', 'Ouvrir le rapport')}<Icon n="arrow-right" /></button></div> : null}
    </div>
  );
}

function LineChart({ labels, series, fmtv, height = 200, band, refLine, refLabel, every }) {
  const [h, setH] = React.useState(null);
  const all = series.flatMap((s) => s.values).concat(band ? [...band.lo, ...band.hi] : []).concat(refLine != null ? [refLine] : []).filter((v) => v != null);
  let mn = Math.min(...all), mx = Math.max(...all); const pad = (mx - mn) * 0.15 || 1; mn -= pad; mx += pad;
  const n = labels.length, X = (i) => (n === 1 ? 50 : (i / (n - 1)) * 100), Y = (v) => 100 - ((v - mn) / (mx - mn)) * 100;
  const path = (vals) => { let s = '', pen = false; vals.forEach((v, i) => { if (v == null) { pen = false; return; } s += (pen ? ' L' : ' M') + X(i).toFixed(2) + ',' + Y(v).toFixed(2); pen = true; }); return s; };
  const area = band ? path(band.hi) + ' ' + band.lo.map((v, i) => [i, v]).reverse().map(([i, v]) => 'L' + X(i).toFixed(2) + ',' + Y(v).toFixed(2)).join(' ') + ' Z' : null;
  const ev = every || Math.ceil(n / 10);
  return (
    <div className="lc" style={{ '--h': height + 'px' }}>
      <div className="lc-ticks">{[mx - pad, (mx + mn) / 2, mn + pad].map((t, i) => <span key={i} style={{ top: Y(t) + '%' }}>{fmtv(t)}</span>)}</div>
      <div className="lc-plot">
        <svg viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
          {[mx - pad, (mx + mn) / 2, mn + pad].map((t, i) => <line key={i} x1="0" x2="100" y1={Y(t)} y2={Y(t)} className="lc-grid" vectorEffect="non-scaling-stroke" />)}
          {area ? <path d={area} className="lc-band" /> : null}
          {refLine != null ? <line x1="0" x2="100" y1={Y(refLine)} y2={Y(refLine)} className="lc-ref" vectorEffect="non-scaling-stroke" /> : null}
          {series.map((s, i) => <path key={i} d={path(s.values)} className={'lc-line lc-' + (s.tone || 'a') + (s.dash ? ' dash' : '')} vectorEffect="non-scaling-stroke" />)}
        </svg>
        {refLine != null && refLabel ? <span className="lc-reflab" style={{ top: Y(refLine) + '%' }}>{refLabel}</span> : null}
        {series.map((s, si) => s.values.map((v, i) => (v != null && (i === h || (h == null && i === s.values.length - 1 - [...s.values].reverse().findIndex((x) => x != null))) ? <i key={si + '-' + i} className={'lc-dot lc-' + (s.tone || 'a')} style={{ left: X(i) + '%', top: Y(v) + '%' }}></i> : null)))}
        <div className="lc-cols">{labels.map((l, i) => <div key={i} onMouseEnter={() => setH(i)} onMouseLeave={() => setH(null)}></div>)}</div>
        {h != null ? <div className="bars-tip lc-tip" style={{ left: X(h) + '%', top: '0' }}><div className="bars-tip-t">{labels[h]}</div>{series.map((s, i) => s.values[h] != null ? <div key={i}><i className={'dot lc-sw lc-' + (s.tone || 'a')}></i>{s.name} <b>{fmtv(s.values[h], true)}</b></div> : null)}{band && band.lo[h] != null ? <div className="muted">{fmtv(band.lo[h], true)} – {fmtv(band.hi[h], true)}</div> : null}</div> : null}
      </div>
      <div className="lc-labels">{labels.map((l, i) => <span key={i} style={{ left: X(i) + '%' }}>{i % ev === 0 || i === n - 1 ? l : ''}</span>)}</div>
    </div>
  );
}

function Waterfall({ steps, fmtv }) {
  const max = Math.max(...steps.map((s) => s.to != null ? Math.max(s.from || 0, s.to) : s.v));
  return (
    <div className="wf">
      {steps.map((s, i) => { const lo = s.total ? 0 : Math.min(s.from, s.to), hi = s.total ? s.v : Math.max(s.from, s.to); return (
        <button key={i} className={'wf-col' + (s.total ? ' total' : ' step') + (s.hl ? ' hl' : '')} onClick={s.onClick}>
          <span className="wf-val tnum">{s.total ? fmtv(s.v) : '−' + fmtv(s.from - s.to)}</span>
          <span className="wf-track"><span className="wf-bar" style={{ bottom: (lo / max) * 100 + '%', height: Math.max(1.5, ((hi - lo) / max) * 100) + '%' }}></span></span>
          <span className="wf-lab">{s.label}</span>
        </button>
      ); })}
    </div>
  );
}

Object.assign(window, { fsum, finK, finScale, finPeriod, FIN_PERIODS, FIN_CMPS, Prov, ProvLegend, FinPicker, Pts, Metric, CalcView, LineChart, Waterfall });
