/* fold.jsx — Dashboard V2 front fold (Scope 3).
   Renders the panels declared in frontend/panels.yml (shipped as D.panels),
   in file order: the fold of five, then the below-fold row. A global
   dimension bar (payer_class / supply_type / product_line — one dimension at
   a time, server-precomputed slices) applies to fold panels whose metrics
   declare that dimension. Aggregates only — no patient-level rows. */
const { D, fmt, fmtSign, pct, monthLabel, Ico, ICONS, slVar } = window.RX;

/* ---------- dimension lens (one active dimension at a time) ---------- */
const LENS_OPTS = [
  { key: "all", label: "Everything", stats: () => D.headlines && D.headlines.all },
  { key: "payer:xpb", label: "Excl. paper-bill", stats: () => D.headlines && D.headlines.xpb },
  { key: "payer:xent", label: "Excl. enteral paper-bill", stats: () => D.headlines && D.headlines.xent },
  { key: "pc:paper_bill", label: "Paper-bill only" },
  { key: "pc:pbm", label: "PBM only" },
  { key: "pl:endo", label: "Endo" },
  { key: "pl:enteral", label: "Enteral" },
  { key: "pl:regular", label: "Regular" },
  { key: "st:pump_supplies", label: "Pump supplies" },
  { key: "st:cgm", label: "CGM supplies" },
  { key: "st:enteral", label: "Enteral supplies" },
];

function lensStats(key) {
  const opt = LENS_OPTS.find(o => o.key === key) || LENS_OPTS[0];
  if (opt.stats) return opt.stats();
  const fv = D.fold_views || {};
  const s = fv[opt.key];
  if (!s) return null;
  // fold_views uses the store's field names; map to the headline-lens shape
  return {
    on_service: s.on_service, on_service_pct: s.on_service_pct,
    reachable: s.reachable_book, new_30d: s.new_30d, churned_30d: s.churned_30d,
    net_30d: s.net_30d, winback: s.winback_15_90, autofill: s.autofill_consent_pct,
    by_line: s.by_line || {},
  };
}

function DimensionBar({ lens, setLens }) {
  const groups = [
    ["Payer class", ["all", "payer:xpb", "payer:xent", "pc:paper_bill", "pc:pbm"]],
    ["Product line", ["pl:endo", "pl:enteral", "pl:regular"]],
    ["Supply type", ["st:pump_supplies", "st:cgm", "st:enteral"]],
  ];
  return (
    <div className="rail" style={{ position: "sticky", top: 0, zIndex: 5 }}>
      <span className="rl">View</span>
      {groups.map(([label, keys]) => (
        <span key={label} style={{ display: "inline-flex", gap: 4, alignItems: "center" }}>
          <span className="rl" style={{ opacity: .6 }}>{label}</span>
          {keys.map(k => (
            <button key={k} className={"ctrl" + (lens === k ? " active" : " ghost")}
              onClick={() => setLens(lens === k ? "all" : k)}>
              {(LENS_OPTS.find(o => o.key === k) || {}).label}
            </button>
          ))}
          <span className="sep" />
        </span>
      ))}
      <span className="spacer" />
      <span className="result">one dimension at a time · counts are patients, deduped across lines</span>
    </div>
  );
}

/* ---------- fold panel 1: fills per day + what's coming ---------- */
function avgPerDay(days, n) {
  const rows = (D.byDay || []).slice(-n);
  if (!rows.length) return null;
  return rows.reduce((a, r) => a + r.c, 0) / rows.length;
}

function dowShape() {
  const rows = (D.byDay || []).slice(-28);
  const sums = [0, 0, 0, 0, 0, 0, 0], counts = [0, 0, 0, 0, 0, 0, 0];
  rows.forEach(r => {
    const wd = (new Date(r.d + "T00:00:00").getDay() + 6) % 7;   // 0=Mon
    sums[wd] += r.c; counts[wd] += 1;
  });
  return sums.map((s, i) => counts[i] ? s / counts[i] : 0);
}

function FillsFlowPanel() {
  const a7 = avgPerDay(7, 7), a28 = avgPerDay(28, 28);
  const shape = dowShape();
  const maxShape = Math.max(...shape, 1);
  const ds = D.due_schedule;
  const due14 = ds ? ds.by_day.slice(0, 14) : [];
  const maxDue = Math.max(...due14.map(r => r[1]), 1);
  const bk = D.backlog || {};
  return (
    <Card title="Fills per day & what's coming"
      desc="Trailing pace, weekly shape, and the deterministic due schedule from staged e-scripts."
     >
      <div className="kpis" style={{ marginBottom: 10 }}>
        <KPI label="Fills/day · 7d" value={a7 == null ? "—" : a7.toFixed(0)} sub="trailing average" />
        <KPI label="Fills/day · 28d" value={a28 == null ? "—" : a28.toFixed(0)} sub="trailing average" />
        <KPI label="Staged next-cycle" value={fmt(bk.real_staged)} sub="e-scripts waiting their turn" />
        <KPI label="Due to fill now" value={fmt(bk.real_staged_due_now)} sub="coverage lapsed — fillable today" accentBar="var(--warn)" />
        <KPI label="Forecast · 7d" value={fmt(D.forecast_windows && D.forecast_windows.d7)} sub="calibrated expectation" />
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: "var(--gap)" }}>
        <div>
          <div className="d" style={{ marginBottom: 4 }}>Day-of-week shape (4-week avg)</div>
          <div style={{ display: "flex", gap: 4, alignItems: "flex-end", height: 64 }}>
            {["M", "T", "W", "T", "F", "S", "S"].map((l, i) => (
              <div key={i} style={{ flex: 1, textAlign: "center" }}>
                <div style={{ height: Math.max(3, 56 * shape[i] / maxShape), background: i >= 5 ? "var(--panel-3)" : "var(--accent)", opacity: i >= 5 ? 1 : .75, borderRadius: 3 }} />
                <div className="d" style={{ fontSize: 10 }}>{l}</div>
              </div>
            ))}
          </div>
        </div>
        <div>
          <div className="d" style={{ marginBottom: 4 }}>
            {ds ? <>Refills due per day · next 14 days <b>(deterministic — Refill Due dates on held scripts)</b>. Weekend dues highlighted — pull them into Friday.</>
              : <>Due-schedule unavailable in this build (no Refill Due data) — trend view only.</>}
          </div>
          {ds &&
            <div style={{ display: "flex", gap: 3, alignItems: "flex-end", height: 64 }}>
              {due14.map((r, i) => (
                <div key={i} style={{ flex: 1, textAlign: "center" }} title={`${r[0]} (${r[2]}): ${r[1]} due`}>
                  <div style={{ height: Math.max(2, 56 * r[1] / maxDue), background: r[3] ? "var(--warn)" : "var(--sl-supplies)", borderRadius: 3 }} />
                  <div className="d" style={{ fontSize: 9 }}>{r[2][0]}</div>
                </div>
              ))}
            </div>}
          {ds &&
            <div className="d" style={{ marginTop: 4 }}>
              {fmt(ds.total_horizon)} due in 90d · <b style={{ color: "var(--warn)" }}>{fmt(ds.weekend_due)} land on weekends</b> · {fmt(ds.past_due_held)} held past due
            </div>}
        </div>
      </div>
    </Card>
  );
}

/* ---------- fold panels 2-4 ---------- */
function OnServicePanel({ H }) {
  if (!H) return <Card title="On service"><Unavail what="Headline metrics" /></Card>;
  return (
    <Card title="On service" desc="Patients whose recurring supply still covers today (supply + grace).">
      <div className="kpis">
        <KPI feature label="On service now" value={fmt(H.on_service)}
          sub={H.reachable ? `${pct(H.on_service_pct, 1)} of ${fmt(H.reachable)} reachable` : ""} />
        <KPI label="New · 30d" value={fmt(H.new_30d)} sub="history-verified first fills" accentBar="var(--pos)" />
      </div>
      {H.by_line && Object.keys(H.by_line).length > 0 &&
        <div className="d" style={{ marginTop: 6 }}>
          {Object.entries(H.by_line).map(([l, n]) => <span key={l} style={{ marginRight: 12 }}><span style={{ color: slVar(l) }}>●</span> {l} <b>{fmt(n)}</b></span>)}
        </div>}
    </Card>
  );
}

function ChurnPanel({ H }) {
  if (!H) return <Card title="Churned"><Unavail what="Headline metrics" /></Card>;
  return (
    <Card title="Churned · last 30 days" desc="Coverage (supply + grace) ran out with no new fill — each churn has a date.">
      <div className="kpis">
        <KPI feature label="Churned · 30d" value={fmt(H.churned_30d)} accentBar="var(--neg)" sub="coverage-lapse definition" />
        <KPI label="Net · 30d" value={fmtSign(H.net_30d)} delta={H.net_30d} sub="new minus churned" />
      </div>
    </Card>
  );
}

function WinbackPanel({ H }) {
  const wb = D.winback;
  const count = H ? H.winback : wb && wb.count;
  const dist = (wb && wb.score_dist) || {};
  const maxD = Math.max(...Object.values(dist), 1);
  const trend = (wb && wb.trend) || [];
  const maxT = Math.max(...trend.map(t => t.count), 1);
  return (
    <Card title="Win-back opportunity" desc="Lapsed 15–90 days — recent enough to call back. Aggregate only; the call roster is the local campaign build.">
      <div className="kpis">
        <KPI feature label="Win-back window" value={fmt(count)} sub={wb ? `avg score ${wb.avg_score}` : ""} accentBar="var(--warn)" />
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "var(--gap)", marginTop: 8 }}>
        <div>
          <div className="d" style={{ marginBottom: 4 }}>Score distribution (hot → right)</div>
          <div style={{ display: "flex", gap: 3, alignItems: "flex-end", height: 48 }}>
            {Object.entries(dist).map(([b, n]) => (
              <div key={b} style={{ flex: 1, textAlign: "center" }} title={`${b}: ${n}`}>
                <div style={{ height: Math.max(2, 42 * n / maxD), background: "var(--accent)", opacity: .45 + .55 * (+b.slice(0, 3)), borderRadius: 3 }} />
                <div className="d" style={{ fontSize: 8 }}>{b.slice(0, 3)}</div>
              </div>
            ))}
          </div>
        </div>
        <div>
          <div className="d" style={{ marginBottom: 4 }}>12-month trend</div>
          <div style={{ display: "flex", gap: 2, alignItems: "flex-end", height: 48 }}>
            {trend.map(t => (
              <div key={t.month} style={{ flex: 1 }} title={`${monthLabel(t.month)}: ${t.count}`}>
                <div style={{ height: Math.max(2, 42 * t.count / maxT), background: "var(--sl-cgm)", borderRadius: 2 }} />
              </div>
            ))}
          </div>
        </div>
      </div>
    </Card>
  );
}

/* ---------- below the fold ---------- */
function VerificationsBelow() {
  const bm = D.benefit_by_month || {};
  const months = Object.keys(bm).sort();
  const maxV = Math.max(...Object.values(bm), 1);
  return (
    <Card title="Verifications by month" desc="Still-held benefit-check entries by entered month — resolved verifications disappear from old months.">
      <div style={{ display: "flex", gap: 3, alignItems: "flex-end", height: 70 }}>
        {months.map(m => (
          <div key={m} style={{ flex: 1, textAlign: "center" }} title={`${monthLabel(m)}: ${fmt(bm[m])}`}>
            <div style={{ height: Math.max(2, 60 * bm[m] / maxV), background: "var(--sl-hardware)", borderRadius: 2 }} />
            <div className="d" style={{ fontSize: 8 }}>{m.slice(5)}</div>
          </div>
        ))}
      </div>
      <div className="d" style={{ marginTop: 4 }}>total {fmt(Object.values(bm).reduce((a, b) => a + b, 0))} since {months[0] ? monthLabel(months[0]) : "—"}</div>
    </Card>
  );
}

function BacklogBelow() {
  const b = D.backlog || {};
  const cls = b.by_class || {};
  return (
    <Card title="Hold backlog" desc="Everything currently on hold, split real vs dummy entries; parked is the pile worth reviewing.">
      <div className="kpis">
        <KPI label="Parked (real)" value={fmt(b.real_parked)} sub="on hold, no recent fill behind it" accentBar="var(--neg)" />
        <KPI label="Real Rx" value={fmt(cls.real)} sub="dispensable" />
        <KPI label="Benefit checks" value={fmt(cls.benefit_check)} sub="dummy — no Rx behind them" />
        <KPI label="Templates" value={fmt(cls.template)} sub="TSP request shells" />
      </div>
      {b.parked_aging &&
        <div className="d" style={{ marginTop: 6 }}>
          parked aging: {Object.entries(b.parked_aging).map(([k, v]) => `${k} · ${fmt(v)}`).join("   ")}
        </div>}
    </Card>
  );
}

function CgmVariantsBelow() {
  const c = D.cgm_outreach || {};
  return (
    <Card title="CGM cohort variants" desc="Context cards beside the main CGM funnel (in Special projects).">
      <div className="kpis">
        <KPI label="Incoming on CGM · 2026" value={fmt(c.incoming_ytd)} sub="arrived already using one — not a win" />
        <KPI label="On CGM pre-2026" value={fmt(c.pre_2026_on_cgm)} sub="shown, not counted" />
        <KPI label="On Dexcom now" value={fmt(c.on_dexcom_now)} sub="informational subset" />
      </div>
    </Card>
  );
}

/* ---------- the fold view (panels.yml-driven) ---------- */
function Fold({ setView }) {
  const [lens, setLens] = useLS("rx_fold_lens", "all");
  const H = lensStats(lens) || lensStats("all");
  const reg = D.panels || { fold: [], below: [] };
  const dimmed = lens !== "all";

  const FOLD_VIZ = {
    fills_flow: () => <FillsFlowPanel />,
    headline_onservice: () => <OnServicePanel H={H} />,
    headline_churn: () => <ChurnPanel H={H} />,
    winback_aggregate: () => <WinbackPanel H={H} />,
    projects: () => <Projects />,
  };
  const BELOW_VIZ = {
    verifications: (p) => <VerificationsBelow key={p.id} />,
    backlog: (p) => <BacklogBelow key={p.id} />,
    cgm_variants: (p) => <CgmVariantsBelow key={p.id} />,
  };

  return (
    <div className="view view-fold">
      <DimensionBar lens={lens} setLens={setLens} />
      {dimmed && <div className="banner-warn" style={{ marginTop: 8 }}>
        Filtered view: <b>{(LENS_OPTS.find(o => o.key === lens) || {}).label}</b> — applies to the on-service, churn and win-back panels. Fills-flow and Special projects always show everything.
      </div>}
      <section id="fold" data-fold-count={reg.fold.length} style={{ display: "grid", gap: "var(--gap)", marginTop: 10 }}>
        {reg.fold.map(p => <div key={p.id} className="fold-slot" data-panel={p.id}>{(FOLD_VIZ[p.viz] || (() => null))()}</div>)}
      </section>
      <div className="d" style={{ margin: "18px 0 6px", textTransform: "uppercase", letterSpacing: 1, fontSize: 11 }}>Below the fold</div>
      <section id="below-fold" style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(320px,1fr))", gap: "var(--gap)" }}>
        {reg.below.map(p => (BELOW_VIZ[p.viz] || (() => null))(p))}
      </section>
      <div className="d" style={{ marginTop: 10 }}>
        Every retired panel's number stays queryable through the metrics dictionary — nothing is deleted, tiers just decide what renders. Deep dives: Product&nbsp;Mix, Patients, Forecast in the sidebar.
      </div>
    </div>
  );
}

window.Fold = Fold;
