/* productmix.jsx — the explorer: ranking + trend + drug×payer matrix */
const { D, fmt, pct, monthLabelShort, slVar } = window.RX;

const TREND_PAL = ["var(--accent)", "var(--sl-enteral)", "var(--sl-hardware)", "var(--sl-cgm)", "var(--sl-acc)"];

/* monthly series for a dimension, respecting the filter */
function monthlySeries(filter, groupBy, idxs, lo, hi) {
  lo = lo == null ? filter.mFrom : lo; hi = hi == null ? filter.mTo : hi;
  return idxs.map(gi => {
    const vals = [];
    for (let m = lo; m <= hi; m++) {
      let s = 0;
      if (groupBy === "drug") {
        for (let pi = 0; pi < D.payers.length; pi++) if (window.RX.cellOK(gi, pi, filter)) s += D.cube[gi][pi][m];
      } else if (groupBy === "payer") {
        for (let di = 0; di < D.drugs.length; di++) if (window.RX.cellOK(di, gi, filter)) s += D.cube[di][gi][m];
      } else if (groupBy === "family") {
        for (let di = 0; di < D.drugs.length; di++) if ((D.drugs[di].family || "Other") === gi)
          for (let pi = 0; pi < D.payers.length; pi++) if (window.RX.cellOK(di, pi, filter)) s += D.cube[di][pi][m];
      } else { // line
        for (let di = 0; di < D.drugs.length; di++) if (D.drugs[di].line === gi)
          for (let pi = 0; pi < D.payers.length; pi++) if (window.RX.cellOK(di, pi, filter)) s += D.cube[di][pi][m];
      }
      vals.push(s);
    }
    return vals;
  });
}

function ProductMix({ filter, agg, chartFilled }) {
  const [groupBy, setGroupBy] = useLS("rx_mix_group", "drug");
  const [metric, setMetric] = useLS("rx_mix_metric", "count");      // ranking metric
  const [matMetric, setMatMetric] = useLS("rx_mix_matm", "count");  // matrix metric
  const [sortPayer, setSortPayer] = useState(-1);                   // -1 = by total

  /* ranking rows */
  let rankRows;
  if (groupBy === "drug") rankRows = agg.byDrug.map((v, i) => ({ key: i, name: D.drugs[i].name, color: slVar(D.drugs[i].line), v }));
  else if (groupBy === "payer") rankRows = agg.byPayer.map((v, i) => ({ key: i, name: D.payers[i].name + (D.payers[i].pb ? " ·paper" : ""), color: "var(--accent)", v }));
  else if (groupBy === "family") {
    const acc = {};
    agg.byDrug.forEach((v, i) => {
      if (!v) return;
      const f = D.drugs[i].family || "Other";
      if (!acc[f]) acc[f] = { key: f, name: f, line: D.drugs[i].line, top: v, v: 0 };
      acc[f].v += v;
      if (v > acc[f].top) { acc[f].top = v; acc[f].line = D.drugs[i].line; }
    });
    rankRows = Object.values(acc).map(r => ({ key: r.key, name: r.name, color: slVar(r.line), v: r.v }));
  }
  else rankRows = D.lines.map(l => ({ key: l, name: l, color: slVar(l), v: agg.byLine[l] || 0 }));
  rankRows = rankRows.filter(r => r.v > 0).sort((a, b) => b.v - a.v);
  const rankMax = rankRows[0] ? rankRows[0].v : 1;

  /* trend: top 5 groups over the selected months (expands to full history if a single month) */
  const topIdxs = rankRows.slice(0, 5).map(r => r.key);
  const single = filter.mTo - filter.mFrom < 1;
  const trLo = single ? 0 : filter.mFrom, trHi = single ? D.months.length - 1 : filter.mTo;
  const trendSeriesVals = monthlySeries(filter, groupBy, topIdxs, trLo, trHi);
  const trendLabels = D.months.slice(trLo, trHi + 1).map(monthLabelShort);
  const trendSeries = topIdxs.map((k, i) => ({
    label: groupBy === "line" ? k : (rankRows[i].name.length > 22 ? rankRows[i].name.slice(0, 22) + "…" : rankRows[i].name),
    values: trendSeriesVals[i],
    color: groupBy === "line" ? slVar(k) : TREND_PAL[i % TREND_PAL.length],
  }));

  /* matrix */
  const mat = window.RX.matrix(filter);
  const rowTotals = mat.cells.map(r => r.reduce((a, b) => a + b, 0));
  const colTotals = mat.payersIdx.map((_, c) => mat.cells.reduce((a, r) => a + r[c], 0));
  const grand = rowTotals.reduce((a, b) => a + b, 0);
  // order rows by total or by a payer column
  const order = mat.drugsIdx.map((_, ri) => ri).sort((a, b) =>
    sortPayer < 0 ? rowTotals[b] - rowTotals[a] : mat.cells[b][sortPayer] - mat.cells[a][sortPayer]);
  const shownOrder = order.filter(ri => rowTotals[ri] > 0).slice(0, 18);
  const matMax = Math.max(1, ...mat.cells.flat());

  const cellDisplay = (ri, ci) => {
    const v = mat.cells[ri][ci];
    if (matMetric === "count") return { txt: v ? fmt(v) : "·", alpha: Math.sqrt(v / matMax) };
    if (matMetric === "rowpct") { const p = rowTotals[ri] ? v / rowTotals[ri] * 100 : 0; return { txt: p >= 0.5 ? p.toFixed(0) + "%" : "·", alpha: p / 100 }; }
    const p = colTotals[ci] ? v / colTotals[ci] * 100 : 0; return { txt: p >= 0.5 ? p.toFixed(0) + "%" : "·", alpha: p / 100 };
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1>Product Mix Explorer</h1>
          <p>Slice top drugs & supplies by payer, service line and month. Set the global filters in the rail, then group, sort and cross-tab below — the whole view recomputes live.</p>
        </div>
      </div>

      {/* view controls */}
      <div className="card" style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap", padding: "11px 14px", marginBottom: "var(--gap)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
          <span className="rl" style={{ fontSize: 11 }}>Group by</span>
          <Segmented value={groupBy} options={[{ value: "drug", label: "Product" }, { value: "family", label: "Brand" }, { value: "line", label: "Service line" }, { value: "payer", label: "Payer" }]} onChange={v => { setGroupBy(v); setSortPayer(-1); }} />
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
          <span className="rl" style={{ fontSize: 11 }}>Metric</span>
          <Segmented value={metric} options={[{ value: "count", label: "Fills" }, { value: "share", label: "Share %" }]} onChange={setMetric} />
        </div>
        <div className="spacer" />
        <div className="result"><b>{fmt(agg.grand)}</b> fills · <b>{rankRows.length}</b> {groupBy === "drug" ? "products" : groupBy === "payer" ? "payers" : groupBy === "family" ? "brands" : "lines"}</div>
      </div>

      <div className="grid" style={{ gridTemplateColumns: "1.35fr 1fr", marginBottom: "var(--gap)" }}>
        <Card title={groupBy === "drug" ? "Top products" : groupBy === "payer" ? "By payer" : groupBy === "family" ? "By brand" : "By service line"}
          desc="Ranked within the current filter set.">
          {rankRows.length ? (
            <div className="rank">
              {rankRows.slice(0, groupBy === "drug" ? 14 : 14).map(r => (
                <div className="rank-row" key={r.key} style={{ gridTemplateColumns: "1fr auto auto" }}>
                  <div className="bar-track">
                    <div className="bar-fill" style={{ width: (r.v / rankMax * 100) + "%", background: r.color, opacity: .82 }} />
                    <div className="bar-label"><span className="sw" style={{ background: r.color }} />{r.name}</div>
                  </div>
                  <div className="val">{metric === "count" ? fmt(r.v) : pct(r.v / agg.grand * 100, 1)}</div>
                  <div className="pct">{metric === "count" ? pct(r.v / agg.grand * 100, 1) : fmt(r.v)}</div>
                </div>
              ))}
            </div>
          ) : <div className="empty">No fills match the current filters.</div>}
        </Card>

        <Card title="Trend" desc={`Top ${topIdxs.length} ${groupBy === "drug" ? "products" : groupBy === "payer" ? "payers" : groupBy === "family" ? "brands" : "lines"}${single ? " · full history" : " over the selected months"}.`}>
          {agg.grand > 0 ? <>
            <AreaLine series={trendSeries} labels={trendLabels} height={236} filled={false} />
            <div className="legend">
              {trendSeries.map((s, i) => <span key={i}><i style={{ background: s.color }} />{s.label}</span>)}
            </div>
          </> : <div className="empty">No data.</div>}
        </Card>
      </div>

      {/* the cross-tab */}
      <Card title="Product × payer cross-tab"
        desc="Every product against every payer for the selected months & lens. Click a payer to sort; switch the read-out to normalize by product or by payer."
        right={<Segmented value={matMetric} options={[{ value: "count", label: "Fills" }, { value: "rowpct", label: "% of product" }, { value: "colpct", label: "% of payer" }]} onChange={setMatMetric} />}>
        {shownOrder.length ? (
          <div className="matrix-wrap" style={{ maxHeight: 560 }}>
            <table className="matrix">
              <thead>
                <tr>
                  <th className="corner" style={{ textAlign: "left", minWidth: 178 }}>{shownOrder.length} of {order.filter(ri => rowTotals[ri] > 0).length} products</th>
                  {mat.payersIdx.map((pi, ci) => (
                    <th key={pi} className="sortable" data-s={sortPayer === ci ? "desc" : null}
                      style={{ cursor: "pointer", minWidth: 78, textAlign: "right", whiteSpace: "nowrap" }}
                      onClick={() => setSortPayer(sortPayer === ci ? -1 : ci)} title={D.payers[pi].name}>
                      {D.payers[pi].name.length > 11 ? D.payers[pi].name.slice(0, 10) + "…" : D.payers[pi].name}
                      {D.payers[pi].pb && <span style={{ color: "var(--warn)" }}> *</span>}
                    </th>
                  ))}
                  <th className="num" style={{ minWidth: 64 }}>Total</th>
                </tr>
              </thead>
              <tbody>
                {shownOrder.map(ri => {
                  const di = mat.drugsIdx[ri];
                  return (
                    <tr key={di}>
                      <th title={D.drugs[di].name}>
                        <span style={{ display: "inline-flex", alignItems: "center", gap: 7 }}>
                          <span className="sw" style={{ width: 7, height: 7, borderRadius: 2, background: slVar(D.drugs[di].line), display: "inline-block", flex: "none" }} />
                          {D.drugs[di].name.length > 24 ? D.drugs[di].name.slice(0, 24) + "…" : D.drugs[di].name}
                        </span>
                      </th>
                      {mat.payersIdx.map((pi, ci) => {
                        const d = cellDisplay(ri, ci);
                        return (
                          <td key={pi}>
                            <span className="cellbg" style={{ background: "var(--accent)", opacity: d.alpha * 0.5 }} />
                            <span style={{ color: d.txt === "·" ? "var(--text-3)" : "var(--text)" }}>{d.txt}</span>
                          </td>
                        );
                      })}
                      <td style={{ fontWeight: 600 }}><span>{fmt(rowTotals[ri])}</span></td>
                    </tr>
                  );
                })}
              </tbody>
              <tfoot>
                <tr>
                  <th className="corner" style={{ textAlign: "left", left: 0 }}>Payer total</th>
                  {colTotals.map((c, ci) => <td key={ci} style={{ fontWeight: 600 }}><span>{fmt(c)}</span></td>)}
                  <td style={{ fontWeight: 700 }}><span>{fmt(grand)}</span></td>
                </tr>
              </tfoot>
            </table>
          </div>
        ) : <div className="empty">No fills match the current filters.</div>}
        <div className="note"><b>* paper-bill payer.</b> Cell shade scales with the selected read-out. Showing the top 18 products by total; refine the line or payer filters to zoom further.</div>
      </Card>
    </div>
  );
}
Object.assign(window, { ProductMix });
