/* patients.jsx — lifecycle: on-service, churn, win-back worklist, lapsed staleness */
const { D, fmt, fmtSign, pct, monthLabel, monthLabelShort, slVar } = window.RX;

/* win-back worklist comes straight from the de-identified D.winback_list export */

function Patients({ filter, chartFilled }) {
  if (!D.headlines) return (
    <div className="page"><div className="page-head"><div><h1>Patients</h1></div></div>
      <Card><Unavail what="Patient lifecycle metrics" /></Card></div>);
  const H = D.headlines[lensKey(filter.pbLens)];
  const curve = D.on_service_curve;
  const marIdx = curve.findIndex(c => c.month === "2026-03");
  const primaryKey = filter.pbLens === "xpb" ? "xpb" : filter.pbLens === "xent" ? "xent" : "all";
  const series = [{ label: lensName(filter.pbLens), values: curve.map(c => c[primaryKey]), color: "var(--accent)" }];
  if (primaryKey !== "all") series.push({ label: "All payers", values: curve.map(c => c.all), color: "var(--text-3)", dashed: true });

  const payerNames = useMemo(() => new Set([...filter.payers].map(i => D.payers[i].name.toUpperCase())), [filter.payers]);
  const prodNames = useMemo(() => filter.products.size === D.drugs.length ? null
    : new Set([...filter.products].map(i => D.drugs[i].name.toUpperCase())), [filter.products]);
  const [sortBy, setSortBy] = useState("fresh");
  const all = D.winback_list || [];
  const work = all
    .filter(r => filter.lines.has(r.service_line)
      && payerNames.has(String(r.payer).toUpperCase())
      && (!prodNames || prodNames.has(String(r.product).toUpperCase()))
      && !(filter.pbLens === "xpb" && (D.payers.find(p => p.name.toUpperCase() === String(r.payer).toUpperCase()) || {}).pb)
      && !(filter.pbLens === "xent" && r.service_line === "Enteral"
        && (D.payers.find(p => p.name.toUpperCase() === String(r.payer).toUpperCase()) || {}).pb))
    .sort((a, b) => sortBy === "fresh" ? a.days_lapsed - b.days_lapsed : b.days_lapsed - a.days_lapsed)
    .slice(0, 80);
  const [copied, setCopied] = useState(false);
  const copy = () => {
    const txt = work.map(r => r.script_number).join("\n");
    navigator.clipboard && navigator.clipboard.writeText(txt);
    setCopied(true); setTimeout(() => setCopied(false), 1600);
  };

  const lineSplit = D.lines.map(l => ({ l, v: H.by_line[l] || 0 })).filter(r => r.v > 0).sort((a, b) => b.v - a.v);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1>Patients</h1>
          <p>Supply-coverage lifecycle from the unified model: on service while the most recent recurring supply (day-supply + grace) still covers today. TSP referrals are tracked separately.</p>
        </div>
        <div className="lens-flag"><span style={{ width: 7, height: 7, borderRadius: 9, background: "var(--accent)", display: "inline-block" }} />Lens · <b>{lensName(filter.pbLens)}</b></div>
      </div>

      <div className="grid" style={{ gridTemplateColumns: "repeat(6,1fr)", marginBottom: "var(--gap)" }}>
        <KPI feature label="On service now" value={fmt(H.on_service)}
          tip={H.on_service_pct != null ? `${pct(H.on_service_pct, 1)} of the recently-active book — currently covered or lapsed ≤90 days (${fmt(H.reachable)} patients).` : null}
          sub={`${H.on_service_pct != null ? pct(H.on_service_pct, 0) + " active · " : ""}${fmt(H.by_line["Pump Supplies"])} pump · ${fmt(H.by_line["Enteral"])} ent · ${fmt(H.by_line["CGM"])} cgm`} />
        <KPI label="New · 30d" value={fmt(H.new_30d)} accentBar="var(--pos)" sub="history-verified" />
        <KPI label="Churned · 30d" value={fmt(H.churned_30d)} accentBar="var(--neg)" sub="coverage lapsed" />
        <KPI label="Net · 30d" value={fmtSign(H.net_30d)} delta={H.net_30d} accentBar={H.net_30d >= 0 ? "var(--pos)" : "var(--neg)"} sub="new − churned" />
        <KPI label="Auto-refill consent" value={pct(H.autofill, 0)} accentBar="var(--sl-cgm)" sub="of on-service" />
        <KPI label="Win-back · 15–90d" value={fmt(H.winback)} accentBar="var(--warn)" sub="recent enough to call" />
      </div>

      <div className="grid" style={{ gridTemplateColumns: "1.5fr 1fr", marginBottom: "var(--gap)" }}>
        <Card title="On-service trend" desc="Month-over-month coverage. Pump/CGM are history-verified to 2025; enteral data begins Mar 2026."
          meta={`${monthLabel(curve[0].month)} – ${monthLabel(curve[curve.length - 1].month)}`}>
          <AreaLine series={series} labels={curve.map(c => monthLabelShort(c.month))} height={250} filled={chartFilled} yFromZero={false}
            annotations={marIdx >= 0 ? [{ idx: marIdx, label: ["Mar 2026 — enteral joins", "model coverage grows, not the business"] }] : []} />
          {primaryKey !== "all" &&
            <div className="legend"><span><i style={{ background: "var(--accent)" }} />{lensName(filter.pbLens)}</span><span><i style={{ background: "var(--text-3)" }} />All payers</span></div>}
        </Card>
        <div className="grid" style={{ gridTemplateRows: "auto 1fr", gap: "var(--gap)" }}>
          <Card title="On service by line" desc="Coverage split, current lens.">
            <div className="rank">
              {lineSplit.map(r => (
                <div className="rank-row" key={r.l} style={{ gridTemplateColumns: "1fr auto auto" }}>
                  <div className="bar-track">
                    <div className="bar-fill" style={{ width: (r.v / lineSplit[0].v * 100) + "%", background: slVar(r.l), opacity: .85 }} />
                    <div className="bar-label"><span className="sw" style={{ background: slVar(r.l) }} />{r.l}</div>
                  </div>
                  <div className="val">{fmt(r.v)}</div>
                  <div className="pct">{pct(r.v / H.on_service * 100, 0)}</div>
                </div>
              ))}
            </div>
          </Card>
          <Card title="Lapsed staleness" desc="Gauge only — action lives in win-back.">
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "var(--gap)" }}>
              {[["60+ d", D.lapsed.d60], ["90+ d", D.lapsed.d90], ["180+ d", D.lapsed.d180]].map(([l, v], i) => (
                <div key={l} style={{ display: "flex", flexDirection: "column", gap: 1, opacity: i === 2 ? .6 : 1 }}>
                  <span className="sub" style={{ color: "var(--text-2)", fontWeight: 500 }}>{l}</span>
                  <span className="mono" style={{ fontSize: 21, fontWeight: 600, letterSpacing: "-.02em" }}>{fmt(v)}</span>
                </div>
              ))}
            </div>
            <div className="note" style={{ marginTop: 12 }}>180+ is history, not a call list.</div>
          </Card>
        </div>
      </div>

      <Card title="Win-back worklist"
        desc="On a chronic supply, coverage lapsed 15–90 days ago — recent enough to call. De-identified: script numbers only, no names, DOB or phone."
        meta={`${work.length} shown of ${all.length}`}
        right={<div style={{ display: "flex", gap: 8 }}>
          <Segmented value={sortBy} options={[{ value: "fresh", label: "Freshest" }, { value: "stale", label: "Most lapsed" }]} onChange={setSortBy} />
          <button className="pillbtn" onClick={copy}><Ico size={13} d={copied ? ICONS.check : ICONS.copy} />{copied ? "Copied" : "Copy scripts"}</button>
        </div>}>
        {D.winback_list == null ? <Unavail what="The win-back worklist" /> :
        <div className="matrix-wrap" style={{ maxHeight: 420, border: "1px solid var(--border)" }}>
          <table>
            <thead><tr>
              <th>Script #</th><th>Service line</th><th>Product</th><th>Payer</th><th>Queue</th><th className="num">Days lapsed</th>
            </tr></thead>
            <tbody>
              {work.map((r, i) => (
                <tr key={i}>
                  <td className="mono">{r.script_number}</td>
                  <td><span style={{ display: "inline-flex", alignItems: "center", gap: 7 }}><span className="sw" style={{ width: 7, height: 7, borderRadius: 2, background: slVar(r.service_line), display: "inline-block" }} />{r.service_line}</span></td>
                  <td style={{ color: "var(--text-2)" }}>{String(r.product).length > 28 ? String(r.product).slice(0, 28) + "…" : r.product}</td>
                  <td>{r.payer}{(D.payers.find(p => p.name.toUpperCase() === String(r.payer).toUpperCase()) || {}).pb && <span className="tag warn" style={{ marginLeft: 6, height: 17 }}>paper</span>}</td>
                  <td style={{ color: "var(--text-2)" }}>{r.queue || "—"}</td>
                  <td className="num"><span className={r.days_lapsed <= 30 ? "tag pos" : r.days_lapsed <= 60 ? "tag warn" : "tag"}>{r.days_lapsed}</span></td>
                </tr>
              ))}
              {!work.length && <tr><td colSpan="6"><div className="empty">No win-back candidates match the current filters.</div></td></tr>}
            </tbody>
          </table>
        </div>}
      </Card>
    </div>
  );
}
Object.assign(window, { Patients });
