/* ============================================================
   gp-detail.jsx — the audit detail: verdict, linkage checks,
   ranked candidate scale (re-rankable), robustness landscape.
   ============================================================ */

// ---- VERDICT BANNER (presentation varies by tweak: flagStyle) ----
function VerdictBanner({ result, decision, flagStyle }) {
  const ok = result.verdict === "VERIFIED";
  const c = ok ? "var(--emerald)" : "var(--rose)";
  const failTxt = result.failed.map((f) => f.label).join(" · ");

  if (flagStyle === "minimal") {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px" }}>
        <VerdictDot verdict={result.verdict} size={9} pulse={!ok} />
        <Mono color={c} size={13} weight={600} style={{ letterSpacing: "0.08em" }}>
          {ok ? "VERIFIED" : "NEEDS REVIEW"}
        </Mono>
        <Mono color="var(--fg-3)" size={11}>{ok ? `winner is #${result.winnerRank} of ${result.validCount}` : failTxt}</Mono>
      </div>
    );
  }

  if (flagStyle === "stamp") {
    return (
      <div style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: "12px 16px", background: "var(--bg-1)",
        borderBottom: "1px solid var(--line)",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <Mono color="var(--fg-3)" size={10}>SELECTION LINKAGE</Mono>
          <Mono color="var(--fg-3)" size={11}>winner is #{result.winnerRank} of {result.validCount} scored combos</Mono>
        </div>
        <div style={{
          padding: "5px 12px", border: "1.5px solid " + c, color: c, borderRadius: 3,
          fontFamily: "var(--mono)", fontSize: 12, fontWeight: 700, letterSpacing: "0.22em",
          transform: "rotate(-1.5deg)", boxShadow: `0 0 0 1px ${c} inset`,
        }}>{ok ? "VERIFIED" : "REVIEW"}</div>
      </div>
    );
  }

  // default: "banner"
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 14, padding: "12px 16px",
      background: `color-mix(in oklab, ${c} 9%, var(--bg-1))`,
      borderBottom: "1px solid " + `color-mix(in oklab, ${c} 35%, var(--line))`,
      borderLeft: `2px solid ${c}`,
    }}>
      <VerdictDot verdict={result.verdict} size={10} pulse={!ok} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 10 }}>
          <Mono color={c} size={14} weight={700} style={{ letterSpacing: "0.1em" }}>
            {ok ? "VERIFIED" : "NEEDS REVIEW"}
          </Mono>
          <Mono color="var(--fg-2)" size={11}>
            {ok
              ? `winner is the top-scoring combo (#${result.winnerRank} of ${result.validCount})`
              : failTxt}
          </Mono>
        </div>
      </div>
      <Pill kind={ok ? "verified" : "flagged"}>{result.checks.filter((x) => x.pass).length}/{result.checks.length} checks</Pill>
    </div>
  );
}

// ---- LINKAGE CHECKLIST ----
function LinkageChecks({ result }) {
  return (
    <div style={{ display: "grid", gap: 0 }}>
      {result.checks.map((chk) => (
        <div key={chk.id} style={{
          display: "flex", alignItems: "center", gap: 12, padding: "11px 16px",
          borderBottom: "1px solid var(--line-soft)",
          background: chk.pass ? "transparent" : "color-mix(in oklab, var(--rose) 7%, transparent)",
        }}>
          <CheckMark pass={chk.pass} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <Mono color={chk.pass ? "var(--fg)" : "var(--rose)"} size={12} weight={500}>{chk.label}</Mono>
            <div style={{ marginTop: 3 }}>
              <Mono color="var(--fg-3)" size={10}>{chk.detail}</Mono>
            </div>
          </div>
          {chk.id === "toprank" && !chk.pass && (
            <Pill kind="flagged">winner ranked #{result.winnerRank}</Pill>
          )}
          {chk.id === "composite" && !chk.pass && chk.mismatch != null && (
            <Pill kind="flagged">Δ {chk.mismatch > 0 ? "+" : ""}{chk.mismatch.toFixed(3)}</Pill>
          )}
          {chk.id === "floor" && chk.pass && chk.margin != null && (
            <Mono color="var(--emerald)" size={10}>+{(chk.margin * 100).toFixed(1)}pp</Mono>
          )}
        </div>
      ))}
    </div>
  );
}

// ---- RANKED CANDIDATE SCALE (re-rankable by any metric) ----
function CandidateScale({ decision, metricKey, setMetricKey, selected, onSelect, showRejected, setShowRejected }) {
  const METRICS = window.GP.verify.METRICS;
  const metric = window.GP.verify.metricByKey(metricKey);
  const winner = decision.winner;
  const winnerKey = JSON.stringify(winner.params);

  const all = decision.sweep.candidates.map((c, i) => ({ ...c, _i: i }));
  const valid = all.filter((c) => c[metricKey] != null && c.composite_score != null);
  const rejected = all.filter((c) => c.composite_score == null);

  // sort by chosen metric
  const sorted = [...valid].sort((a, b) =>
    metric.higher ? b[metricKey] - a[metricKey] : a[metricKey] - b[metricKey]);

  // normalize for bar widths
  const vals = valid.map((c) => c[metricKey]);
  const lo = Math.min(...vals), hi = Math.max(...vals);
  const span = (hi - lo) || 1;
  const fracOf = (v) => metric.higher ? (v - lo) / span : (hi - v) / span;

  const floor = decision.win_rate_floor;
  const isWinner = (c) => JSON.stringify(c.params) === winnerKey;
  const engineTopByMetric = sorted.length && isWinner(sorted[0]);

  const paramSummary = (c) => {
    const strat = window.GP.STRATEGIES.find((s) => s.id === decision.strategy_id);
    return Object.keys(strat.paramSpace).map((k) => `${k.split("_")[0]}=${c.params[k]}`).join(" ");
  };

  return (
    <div>
      <SectionBar num="03" title="Candidate field — ranked on one scale" right={
        <div style={{ display: "flex", gap: 4 }}>
          {METRICS.map((m) => (
            <button key={m.key} onClick={() => setMetricKey(m.key)} style={{
              padding: "4px 8px", background: metricKey === m.key ? "var(--cyan)" : "transparent",
              color: metricKey === m.key ? "var(--bg-0)" : "var(--fg-3)",
              border: "1px solid " + (metricKey === m.key ? "var(--cyan)" : "var(--line)"),
              borderRadius: 2, cursor: "pointer", fontFamily: "var(--mono)", fontSize: 9,
              letterSpacing: "0.1em",
            }}>{m.short}</button>
          ))}
        </div>
      } />

      <div style={{ padding: "10px 14px 6px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 8 }}>
          <Mono color="var(--fg-3)" size={10}>
            sorting {sorted.length} scored combos by <span style={{ color: "var(--cyan)" }}>{metric.label}</span>
            {metric.higher ? " (high→low)" : " (low→high)"}
          </Mono>
          {!engineTopByMetric && (
            <Pill kind="warn" dot>engine pick is #{sorted.findIndex(isWinner) + 1} by {metric.short}</Pill>
          )}
        </div>

        <div style={{ display: "grid", gap: 3 }}>
          {sorted.map((c, rank) => {
            const win = isWinner(c);
            const sel = selected != null && c._i === selected;
            const passFloor = c.win_rate_frac >= floor;
            const barColor = win ? "var(--emerald)" : passFloor ? "var(--cyan)" : "var(--rose)";
            return (
              <div key={c._i} onClick={() => onSelect(sel ? null : c._i)} style={{
                display: "grid", gridTemplateColumns: "26px 1fr 64px", alignItems: "center", gap: 10,
                padding: "5px 8px", cursor: "pointer", borderRadius: 3,
                background: sel ? "var(--bg-2)" : win ? "color-mix(in oklab, var(--emerald) 8%, transparent)" : "transparent",
                border: "1px solid " + (win ? "color-mix(in oklab, var(--emerald) 40%, transparent)" : sel ? "var(--line)" : "transparent"),
              }}>
                <Mono color={win ? "var(--emerald)" : "var(--fg-3)"} size={10} weight={win ? 700 : 400}>
                  #{rank + 1}
                </Mono>
                <div style={{ minWidth: 0 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 3 }}>
                    {win && <Pill kind="winner" style={{ fontSize: 8, padding: "1px 5px" }}>winner ◆</Pill>}
                    <Mono color="var(--fg-3)" size={9} style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                      {paramSummary(c)}
                    </Mono>
                  </div>
                  <Bar frac={fracOf(c[metricKey])} color={barColor} height={5} glow={win} />
                </div>
                <div style={{ textAlign: "right" }}>
                  <MetricVal metricKey={metricKey} value={c[metricKey]} size={11} weight={win ? 700 : 500} />
                </div>
              </div>
            );
          })}
        </div>

        {rejected.length > 0 && (
          <div style={{ marginTop: 8, paddingTop: 8, borderTop: "1px solid var(--line-soft)" }}>
            <button onClick={() => setShowRejected(!showRejected)} style={{
              background: "transparent", border: "none", cursor: "pointer", padding: 0,
              display: "flex", alignItems: "center", gap: 8,
            }}>
              <Mono color="var(--fg-3)" size={10}>{showRejected ? "▾" : "▸"} {rejected.length} zero-trade / discarded combos</Mono>
            </button>
            {showRejected && (
              <div style={{ marginTop: 6, display: "grid", gap: 3 }}>
                {rejected.map((c) => (
                  <div key={c._i} style={{ display: "flex", alignItems: "center", gap: 10, padding: "4px 8px", opacity: 0.6 }}>
                    <span style={{ width: 26 }}><Mono color="var(--rose)" size={9}>✕</Mono></span>
                    <Mono color="var(--fg-3)" size={9} style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{paramSummary(c)}</Mono>
                    <Mono color="var(--fg-3)" size={9}>{c.rationale}</Mono>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

// ---- ROBUSTNESS LANDSCAPE ----
function RobustnessPanel({ decision }) {
  const rob = window.GP.verify.robustness(decision);
  const slice = window.GP.verify.paramSlice(decision);
  const ROB_META = {
    PLATEAU:   { c: "var(--emerald)", txt: "ROBUST PLATEAU", note: "the winner sits on a broad shelf of high scores — low overfit risk" },
    SUPPORTED: { c: "var(--cyan)",    txt: "SUPPORTED PEAK", note: "several nearby combos also score highly — reasonable confidence" },
    NARROW:    { c: "var(--amber)",   txt: "NARROW PEAK",    note: "few neighbors score highly — watch for fragility" },
    SPIKE:     { c: "var(--rose)",    txt: "LONE SPIKE",     note: "the winner is an isolated high — elevated overfit risk" },
    UNKNOWN:   { c: "var(--fg-3)",    txt: "INSUFFICIENT",   note: "not enough scored combos to judge" },
  };
  const meta = ROB_META[rob.kind];

  const best = Math.max(...slice.points.filter((p) => p.best != null).map((p) => p.best));
  const peak = decision.winner.composite_score;
  const bandFrac = rob.band / (best || 1);

  return (
    <div>
      <SectionBar num="04" title="Robustness — is the winner a plateau or a spike?" right={
        <Pill kind={rob.kind === "PLATEAU" ? "verified" : rob.kind === "SPIKE" ? "flagged" : rob.kind === "NARROW" ? "warn" : "accent"} dot>{meta.txt}</Pill>
      } />
      <div style={{ padding: "12px 16px", display: "grid", gridTemplateColumns: "1fr 200px", gap: 18 }}>
        {/* 1-D param slice */}
        <div>
          <Mono color="var(--fg-3)" size={10}>best composite by <span style={{ color: "var(--cyan)" }}>{slice.param}</span> (winner highlighted)</Mono>
          <div style={{ display: "flex", alignItems: "flex-end", gap: 10, height: 110, marginTop: 12, position: "relative" }}>
            {/* 92% band line */}
            <div style={{ position: "absolute", left: 0, right: 0, bottom: 16 + bandFrac * 94, borderTop: "1px dashed color-mix(in oklab, var(--emerald) 45%, transparent)", pointerEvents: "none" }}>
              <Mono color="var(--emerald)" size={8} style={{ position: "absolute", right: 0, top: -11 }}>89% of peak</Mono>
            </div>
            {slice.points.map((p) => {
              const h = p.best != null ? (p.best / best) * 94 : 0;
              const strong = p.best != null && p.best >= rob.band;
              return (
                <div key={p.value} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 0 }}>
                  <Mono color={p.isWinner ? "var(--emerald)" : "var(--fg-3)"} size={9} weight={p.isWinner ? 700 : 400} style={{ marginBottom: 4 }}>
                    {p.best != null ? p.best.toFixed(2) : "—"}
                  </Mono>
                  <div style={{
                    width: "100%", height: Math.max(2, h),
                    background: p.isWinner ? "var(--emerald)" : strong ? "color-mix(in oklab, var(--cyan) 78%, transparent)" : "color-mix(in oklab, var(--fg-3) 55%, transparent)",
                    boxShadow: p.isWinner ? "0 0 8px var(--emerald)" : "none",
                    borderRadius: "1px 1px 0 0",
                  }} />
                  <Mono color={p.isWinner ? "var(--emerald)" : "var(--fg-3)"} size={9} weight={p.isWinner ? 700 : 400} style={{ marginTop: 5 }}>{p.value}</Mono>
                </div>
              );
            })}
          </div>
        </div>
        {/* neighborhood readout */}
        <div style={{ display: "flex", flexDirection: "column", gap: 10, justifyContent: "center", borderLeft: "1px solid var(--line-soft)", paddingLeft: 16 }}>
          <div>
            <Mono color={meta.c} size={22} weight={700}>{rob.neighborsHigh}</Mono>
            <Mono color="var(--fg-3)" size={11}> / {rob.neighborsTotal}</Mono>
            <div><Label>combos within 11% of peak</Label></div>
          </div>
          <div>
            <Mono color="var(--emerald)" size={15} weight={600}>{rob.clearFloorHigh}</Mono>
            <div><Label>of those also clear the floor</Label></div>
          </div>
          <div>
            <Mono color="var(--fg)" size={13} weight={500}>{(rob.pctOfPeak * 100).toFixed(0)}%</Mono>
            <div><Label>mean of strong cluster vs peak</Label></div>
          </div>
          <Mono color={meta.c} size={10} style={{ lineHeight: 1.5 }}>{meta.note}</Mono>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { VerdictBanner, LinkageChecks, CandidateScale, RobustnessPanel });
