// ═══════════════════════════════════════════════════════════════
// inventory-kpi.jsx — cost per case, and the day's short list (Step 9)
// ═══════════════════════════════════════════════════════════════
//
// WHAT THIS IS (in plain English):
//
//   Cost per case (Reports → Cost per case). What the OR actually spent on
//   each case, from the items the Dispensary wrote off when the case was
//   closed. Shown two ways, because they answer different questions:
//   supplies on their own — the number worth comparing between similar
//   cases — and supplies plus the lens, which is the true cost of goods but
//   is mostly the lens. Cataracts are split by CPT where the worklist says.
//
//   The day's short list (top of the Stock Room dashboard). Everything that
//   needs somebody's attention, in one place: stock about to expire, items
//   under PAR, prices that moved, invoices not reconciled, the controlled
//   drawer not counted, half tablets not witnessed, tomorrow's lenses not
//   checked. This is the daily digest, except it lives where Heather
//   already is instead of in an email she has to open.
// ═══════════════════════════════════════════════════════════════

const kpiMoney = (n) => (n == null || isNaN(n)) ? '—' : '$' + Number(n).toFixed(2);
const kpiTomorrow = () => { const d = new Date(invToday() + 'T12:00:00'); d.setDate(d.getDate() + 1); return d.toLocaleDateString('en-CA'); };

async function kpiFetch(params) {
  const q = new URLSearchParams(Object.fromEntries(Object.entries(params || {}).filter(([, v]) => v))).toString();
  const r = await fetch('/api/inventory/kpi' + (q ? '?' + q : ''), { headers: InvApi.headers() });
  const b = await r.json().catch(() => ({}));
  if (!r.ok) throw new Error(b.error || 'Could not work out the cost per case');
  return b;
}

// ─── The day's short list ────────────────────────────────────────
function InvTodayPanel({ stores, alerts, setTab }) {
  const POS = stores.purchase_orders.data || [];
  const PULLS = stores.lens_pulls.data || [];
  const [cs, setCs] = invUseState(null);
  const [pull, setPull] = invUseState(null);
  const tomorrow = kpiTomorrow();

  invUseEffect(() => {
    let alive = true;
    fetch('/api/inventory/controlled?date=' + invToday(), { headers: InvApi.headers() })
      .then((r) => r.json()).then((d) => { if (alive) setCs(d); }).catch(() => {});
    InvApi.lensPull({ date: tomorrow, scans: [] })
      .then((d) => { if (alive) setPull(d); }).catch(() => {});
    return () => { alive = false; };
  }, [tomorrow]);

  const c = alerts ? alerts.counts : null;
  const unreconciled = POS.filter((p) => (p.status === 'placed' || p.status === 'partial' || p.status === 'completed') && !p.reconciled).length;
  const pullRecord = PULLS.find((r) => r.date === tomorrow);
  const pullNeeded = pull && pull.slots && pull.slots.length && !(pullRecord && pullRecord.locked);

  const rows = [];
  if (c && c.expired) rows.push(['var(--red)', `${c.expired} item(s) already expired`, 'inventory']);
  if (c && c.expiringSoon) rows.push(['var(--amber)', `${c.expiringSoon} item(s) expiring within a month`, 'inventory']);
  if (c && c.belowPar) rows.push(['var(--amber)', `${c.belowPar} item(s) below PAR`, 'reports']);
  if (c && c.priceChanges) rows.push(['var(--gray-600)', `${c.priceChanges} price change(s) since the catalog was set`, 'inventory']);
  if (unreconciled) rows.push(['var(--gray-600)', `${unreconciled} purchase order(s) with no invoice reconciled against them`, 'invoices']);
  if (cs && cs.drugs && cs.drugs.length && !cs.allCounted) rows.push(['var(--red)', `Controlled drawer not counted today (${cs.counted} of ${cs.drugCount} drugs)`, null]);
  if (cs && cs.mismatches) rows.push(['var(--red)', `${cs.mismatches} controlled drug(s) counted differently from the system`, 'reports']);
  if (cs && cs.wasteDue && cs.wasteDue.length) rows.push(['var(--red)', `${cs.wasteDue.length} part tablet(s) waiting for a witness`, null]);
  if (pullNeeded) rows.push(['var(--amber)', `Tomorrow's lenses not checked off yet (${pull.slots.filter((s) => s.matched).length} of ${pull.slots.length})`, 'lenses']);

  return (
    <div className="card" style={{ margin: '0 0 14px' }}>
      <div className="card-header">Needs attention</div>
      <div className="card-body">
        {rows.length === 0
          ? <div style={{ color: 'var(--green)', fontWeight: 600, fontSize: '0.9rem' }}>✓ Nothing needs attention right now.</div>
          : (
            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
              <tbody>
                {rows.map(([color, text, tab], i) => (
                  <tr key={i}>
                    <td style={{ ...invCell, width: 10, color, fontWeight: 700 }}>•</td>
                    <td style={{ ...invCell, color }}>{text}</td>
                    <td style={{ ...invCell, textAlign: 'right', width: 110 }}>
                      {tab
                        ? <button className="btn btn-sm btn-outline" onClick={() => setTab(tab)}>Open</button>
                        : <span style={{ fontSize: '0.74rem', color: 'var(--gray-500)' }}>on the schedule</span>}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
      </div>
    </div>
  );
}

// ─── Cost per case ───────────────────────────────────────────────
function InvCostPerCase() {
  const ninetyBack = () => { const d = new Date(invToday() + 'T12:00:00'); d.setDate(d.getDate() - 90); return d.toLocaleDateString('en-CA'); };
  const [from, setFrom] = invUseState(ninetyBack);
  const [to, setTo] = invUseState(invToday);
  const [data, setData] = invUseState(null);
  const [err, setErr] = invUseState('');
  const [showCases, setShowCases] = invUseState(false);

  invUseEffect(() => { setData(null); setErr(''); kpiFetch({ from, to }).then(setData).catch((e) => setErr(e.message)); }, [from, to]);

  const exportCsv = () => {
    if (!data) return;
    const rows = [['Date', 'Case type', 'Procedure', 'Eye', 'Lens', 'Supplies', 'Lens cost', 'Total', 'Cancelled']];
    data.cases.forEach((c) => rows.push([c.date, c.type, c.procedure, c.eye, c.lens, c.supplies, c.iol, c.total, c.cancelled ? 'yes' : '']));
    const csv = rows.map((r) => r.map((x) => `"${String(x == null ? '' : x).replace(/"/g, '""')}"`).join(',')).join('\n');
    const a = document.createElement('a');
    a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
    a.download = `supply_cost_per_case_${from}_to_${to}.csv`;
    a.click();
  };

  if (err) return <div className="card"><div className="card-body" style={{ color: 'var(--red)' }}>⚠️ {err}</div></div>;
  return (
    <div>
      <p style={{ fontSize: '0.85rem', color: 'var(--gray-600)', maxWidth: 780 }}>
        What each case consumed, from the items written off when it was closed. Supplies on their own is the number worth comparing between similar cases; the lens is shown beside it because it usually dwarfs everything else.
      </p>
      <div style={{ display: 'flex', gap: 12, alignItems: 'flex-end', flexWrap: 'wrap', marginBottom: 12 }}>
        <InvField label="From"><input type="date" value={from} onChange={(e) => setFrom(e.target.value)} /></InvField>
        <InvField label="To"><input type="date" value={to} onChange={(e) => setTo(e.target.value)} /></InvField>
        <span style={{ flex: 1 }} />
        {data && <button className="btn btn-outline btn-sm" onClick={exportCsv}>↓ Export cases (CSV)</button>}
      </div>

      {!data ? <div style={{ color: 'var(--gray-500)', padding: 12 }}>Working it out…</div> : data.totals.cases === 0 ? (
        <div className="card" style={{ maxWidth: 680 }}><div className="card-body" style={{ color: 'var(--gray-500)', fontSize: '0.86rem' }}>
          No closed cases in this period yet. A case appears here once it is marked Complete and its Dispensary is finalized.
        </div></div>
      ) : (
        <div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(170px, 1fr))', gap: 10, marginBottom: 14 }}>
            {[['Cases', data.totals.cases, ''],
              ['Supplies spend', kpiMoney(data.totals.suppliesSpend), 'excluding lenses'],
              ['Total spend', kpiMoney(data.totals.spend), 'supplies + lenses'],
              ['Cancelled cases', data.totals.cancelled, data.totals.cancelled ? kpiMoney(data.totals.cancelledSpend) + ' opened anyway' : '']]
              .map(([label, value, sub]) => (
                <div key={label} className="card" style={{ margin: 0 }}><div className="card-body">
                  <div style={{ fontSize: '0.7rem', textTransform: 'uppercase', color: 'var(--gray-500)', fontWeight: 600 }}>{label}</div>
                  <div style={{ fontSize: '1.4rem', fontWeight: 700, color: 'var(--navy)' }}>{value}</div>
                  {sub ? <div style={{ fontSize: '0.74rem', color: 'var(--gray-500)' }}>{sub}</div> : null}
                </div></div>
              ))}
          </div>

          <div className="card" style={{ margin: '0 0 14px' }}>
            <div className="tbl-wrap" style={{ overflowX: 'auto' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <thead><tr>
                  <th style={invTh}>Case type</th>
                  <th style={{ ...invTh, textAlign: 'right' }}>Cases</th>
                  <th style={{ ...invTh, textAlign: 'right' }}>Supplies / case</th>
                  <th style={{ ...invTh, textAlign: 'right' }}>Lens / case</th>
                  <th style={{ ...invTh, textAlign: 'right' }}>Total / case</th>
                  <th style={{ ...invTh, textAlign: 'right' }}>Spend</th>
                </tr></thead>
                <tbody>
                  {data.byType.map((g) => (
                    <tr key={g.type}>
                      <td style={invCell}>{g.type}{g.type === 'Cataract (no code)' ? <div style={{ fontSize: '0.72rem', color: 'var(--gray-500)' }}>the worklist didn't say 66984 or 66982</div> : null}</td>
                      <td style={{ ...invCell, textAlign: 'right' }}>{g.cases}</td>
                      <td style={{ ...invCell, textAlign: 'right', fontWeight: 700 }}>{kpiMoney(g.avgSupplies)}</td>
                      <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(g.avgIol)}</td>
                      <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(g.avgTotal)}</td>
                      <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(g.totalSpend)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          {data.trend.length > 1 && (
            <div className="card" style={{ margin: '0 0 14px' }}>
              <div className="card-header">Month by month</div>
              <div className="card-body">
                <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                  <thead><tr><th style={invTh}>Month</th><th style={{ ...invTh, textAlign: 'right' }}>Cases</th><th style={{ ...invTh, textAlign: 'right' }}>Supplies / case</th><th style={{ ...invTh, textAlign: 'right' }}>Total / case</th><th style={invTh} /></tr></thead>
                  <tbody>
                    {(() => {
                      const max = Math.max(...data.trend.map((t) => t.avgSupplies), 1);
                      return data.trend.map((t) => (
                        <tr key={t.month}>
                          <td style={invCell}>{t.month}</td>
                          <td style={{ ...invCell, textAlign: 'right' }}>{t.cases}</td>
                          <td style={{ ...invCell, textAlign: 'right', fontWeight: 700 }}>{kpiMoney(t.avgSupplies)}</td>
                          <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(t.avgTotal)}</td>
                          <td style={{ ...invCell, width: '40%' }}>
                            <div style={{ background: 'var(--teal)', height: 10, borderRadius: 5, width: `${Math.max(2, (t.avgSupplies / max) * 100)}%` }} />
                          </td>
                        </tr>
                      ));
                    })()}
                  </tbody>
                </table>
              </div>
            </div>
          )}

          {data.totals.unmatched > 0 && (
            <div style={{ fontSize: '0.8rem', color: 'var(--gray-600)', marginBottom: 10 }}>
              {data.totals.unmatched} case(s) had supplies written off but no matching case record — usually a chart deleted after the fact. They are in the export but not in the averages above.
            </div>
          )}

          <button className="btn btn-outline btn-sm" onClick={() => setShowCases(!showCases)}>{showCases ? 'Hide' : 'Show'} the {data.cases.length} individual cases</button>
          {showCases && (
            <div className="card" style={{ margin: '10px 0 0' }}>
              <div className="tbl-wrap" style={{ overflowX: 'auto', maxHeight: 460 }}>
                <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                  <thead><tr><th style={invTh}>Date</th><th style={invTh}>Type</th><th style={invTh}>Lens</th><th style={{ ...invTh, textAlign: 'right' }}>Supplies</th><th style={{ ...invTh, textAlign: 'right' }}>Lens</th><th style={{ ...invTh, textAlign: 'right' }}>Total</th></tr></thead>
                  <tbody>
                    {data.cases.map((c) => (
                      <tr key={c.refId} style={c.cancelled ? { opacity: 0.6 } : undefined}>
                        <td style={invCell}>{c.date}</td>
                        <td style={invCell}>{c.type}{c.cancelled ? <InvTag color="var(--red)">cancelled</InvTag> : null}{c.bilateralSameDay ? <InvTag>both eyes</InvTag> : null}</td>
                        <td style={{ ...invCell, fontSize: '0.8rem' }}>{c.lens || '—'}</td>
                        <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(c.supplies)}</td>
                        <td style={{ ...invCell, textAlign: 'right' }}>{kpiMoney(c.iol)}</td>
                        <td style={{ ...invCell, textAlign: 'right', fontWeight: 600 }}>{kpiMoney(c.total)}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}
