/* ============================================================
   Post-Call Analysis: triage table screen.
   ============================================================ */
;(function(){
const { DIMS, SUBDIMS, RISK_WARN, RISK_BAD, severityColor, bandColor, qualityLabel, reviewStatus, fmtTime, fmtScore } = window.AIData;
const { Icon, Button, Badge, Chip, Tooltip, SeverityBar, useIsMobile } = window.UI;

const FLAG_THRESHOLD = RISK_WARN; // 0.35, docs' "noticeable degradation" band
const fmtPct = (v) => `${Math.round(v * 100)}%`;

/* ---- aggregate stat tile ---- */
function StatTile({ label, value, unit, sub, accent }) {
  return (
    <div style={{ flex: "1 1 140px", minWidth: 0, background: "var(--surface-card)", border: "1px solid var(--border-subtle)", borderRadius: "var(--radius-md)", padding: "16px 18px" }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--text-tertiary)" }}>{label}</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 4, marginTop: 12 }}>
        <span style={{ fontFamily: "var(--font-display)", fontSize: 32, lineHeight: 1, letterSpacing: "-0.02em", color: accent || "var(--text-primary)" }}>{value}</span>
        {unit && <span style={{ fontFamily: "var(--font-display)", fontSize: 17, color: "var(--text-tertiary)" }}>{unit}</span>}
      </div>
      {sub && <div style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--text-tertiary)", marginTop: 9 }}>{sub}</div>}
    </div>
  );
}

/* ---- score cell ---- */
function ScoreCell({ value, dim, headline }) {
  const neutral = !!dim.neutral;
  // risk (headline): blue severity ramp · loudness (neutral): no color · others: traffic-light band
  const barColor = neutral ? undefined : headline ? severityColor(Math.max(0.24, value)) : bandColor(value);
  const numColor = neutral ? "var(--text-secondary)" : barColor;
  return (
    <td style={{ padding: "13px 14px", verticalAlign: "middle" }}>
      <div style={{ display: "flex", alignItems: "baseline", gap: 7, marginBottom: 7 }}>
        {headline && <span style={{ width: 7, height: 7, borderRadius: "50%", background: barColor, flex: "0 0 auto", transform: "translateY(-1px)" }} />}
        <span style={{ fontFamily: "var(--font-mono)", fontSize: headline ? 16 : 13.5, fontWeight: headline ? 600 : 500, color: numColor }}>{fmtScore(value)}</span>
      </div>
      <SeverityBar value={value} neutral={neutral} color={barColor} height={headline ? 4 : 3} />
    </td>
  );
}

/* ---- column header with sort + tooltip ---- */
function HeadCell({ dim, sortKey, sortDir, onSort, align = "left" }) {
  const active = sortKey === dim.key;
  return (
    <th onClick={() => onSort(dim.key)} style={{ padding: "16px 14px 12px", textAlign: align, verticalAlign: "bottom", fontWeight: 500, fontSize: 11, letterSpacing: "0.05em", textTransform: "uppercase", fontFamily: "var(--font-mono)", lineHeight: 1.3, color: active ? "var(--text-primary)" : "var(--text-tertiary)", cursor: "pointer", userSelect: "none" }}>
      {dim.label}
      {active && <Icon name="chevron.down" size={11} color="var(--blue-40)" style={{ transform: sortDir === "asc" ? "rotate(180deg)" : "none", marginLeft: 4, verticalAlign: "middle" }} />}
    </th>
  );
}

function Row({ call, onOpen, riskMetric, driverFilter, onDriver, isMobile }) {
  const [hover, setHover] = React.useState(false);
  const riskVal = riskMetric === "p95" ? call.metrics.p95 : call.scores.risk_score;
  const rs = reviewStatus(riskVal); // review signal follows the selected metric
  const drv = call.driver;
  const showDriver = rs.needsReview && drv && drv.value > 0.12;
  return (
    <tr onClick={() => onOpen(call)} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ cursor: "pointer", background: hover ? "rgba(255,255,255,0.025)" : "transparent", borderTop: "1px solid var(--border-subtle)", transition: "background var(--dur-fast)" }}>
      {/* recording */}
      <td style={{ padding: "14px 16px", verticalAlign: "middle" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, minWidth: 0 }}>
          <div style={{ width: 34, height: 34, flex: "0 0 auto", borderRadius: "var(--radius-md)", background: hover ? "var(--blue-50)" : "var(--surface-sunken)", border: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", justifyContent: "center", transition: "background var(--dur-fast)" }}>
            <Icon name="play.fill" size={13} color={hover ? "#fff" : "var(--text-tertiary)"} style={{ marginLeft: 2 }} />
          </div>
          {/* truncate long names with an ellipsis; full name on hover (title) and in the modal header */}
          <div title={call.file} style={{ fontFamily: "var(--font-mono)", fontSize: 13.5, color: "var(--text-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: isMobile ? 168 : 200 }}>{call.file}</div>
        </div>
      </td>
      {/* duration (hidden on mobile) */}
      {!isMobile && <td style={{ padding: "13px 14px", fontFamily: "var(--font-mono)", fontSize: 13, color: "var(--text-secondary)", whiteSpace: "nowrap" }}>{fmtTime(call.durationSec)}</td>}
      {/* review status: colored dot only */}
      <td style={{ padding: "13px 14px" }}>
        <Tooltip label={rs.label} width={150}>
          <span style={{ display: "inline-flex", width: 16, height: 16, alignItems: "center", justifyContent: "center" }}>
            <span style={{ width: 10, height: 10, borderRadius: "50%", background: rs.color, boxShadow: rs.key !== "ok" ? `0 0 0 4px ${rs.glow}` : "none" }} />
          </span>
        </Tooltip>
      </td>
      {/* headline risk (mean or p95) */}
      <ScoreCell value={riskVal} dim={DIMS[0]} headline />
      {/* % degraded: fraction of windows in the Warn+ band */}
      <td style={{ padding: "13px 14px", verticalAlign: "middle" }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 7, marginBottom: 7 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 13.5, fontWeight: 500, color: "var(--text-primary)" }}>{fmtPct(call.metrics.fracDegraded)}</span>
        </div>
        <SeverityBar value={call.metrics.fracDegraded} height={3} />
      </td>
      {/* driver: the worst dimension ("why"), click to filter */}
      <td style={{ padding: "13px 14px", verticalAlign: "middle", whiteSpace: "nowrap" }}>
        {showDriver
          ? <span onClick={(e) => { e.stopPropagation(); onDriver(drv.key); }} style={{ cursor: "pointer" }}>
              <Badge tone={driverFilter === drv.key ? "accent" : "neutral"} dot>{drv.short}</Badge>
            </span>
          : <span style={{ color: "var(--text-tertiary)" }}>-</span>}
      </td>
      {/* sub-dimensions (hidden on mobile; available in the modal) */}
      {!isMobile && SUBDIMS.map((d) => <ScoreCell key={d.key} value={call.scores[d.key]} dim={d} headline={false} />)}
    </tr>
  );
}

function Table({ calls, onOpen, onLoadClick, isCustom, restored, onReset, riskMetric, setRiskMetric }) {
  const isMobile = useIsMobile();
  const [query, setQuery] = React.useState("");
  const [flaggedOnly, setFlaggedOnly] = React.useState(false);
  const [driverFilter, setDriverFilter] = React.useState(null);
  const [sortKey, setSortKey] = React.useState("risk_score");
  const [sortDir, setSortDir] = React.useState("desc");

  const onSort = (key) => {
    if (key === sortKey) setSortDir((d) => (d === "desc" ? "asc" : "desc"));
    else { setSortKey(key); setSortDir(key === "file" ? "asc" : "desc"); }
  };
  const driverLabelOf = (key) => key === "speaker_loudness" ? "Low loudness" : ((SUBDIMS.find((d) => d.key === key) || {}).short || key);
  // the active risk value for a call (mean or p95) drives every review signal
  const riskOf = (c) => riskMetric === "p95" ? c.metrics.p95 : c.scores.risk_score;

  const view = React.useMemo(() => {
    let list = calls.filter((c) =>
      (!flaggedOnly || riskOf(c) >= FLAG_THRESHOLD) &&
      (!driverFilter || (c.driver && c.driver.key === driverFilter && reviewStatus(riskOf(c)).needsReview)) &&
      (!query || c.file.toLowerCase().includes(query.toLowerCase()))
    );
    const dir = sortDir === "desc" ? -1 : 1;
    list = [...list].sort((a, b) => {
      let av, bv;
      if (sortKey === "file") { av = a.file; bv = b.file; return av < bv ? dir : av > bv ? -dir : 0; }
      if (sortKey === "duration") { av = a.durationSec; bv = b.durationSec; }
      else if (sortKey === "fracDegraded") { av = a.metrics.fracDegraded; bv = b.metrics.fracDegraded; }
      else if (sortKey === "risk_score") { av = riskMetric === "p95" ? a.metrics.p95 : a.scores.risk_score; bv = riskMetric === "p95" ? b.metrics.p95 : b.scores.risk_score; }
      else { av = a.scores[sortKey]; bv = b.scores[sortKey]; }
      return (av - bv) * dir;
    });
    return list;
  }, [calls, query, flaggedOnly, driverFilter, riskMetric, sortKey, sortDir]);

  // aggregates
  const agg = React.useMemo(() => {
    const n = calls.length;
    const avgQ = calls.reduce((s, c) => s + c.scores.risk_score, 0) / (n || 1);
    const flagged = calls.filter((c) => riskOf(c) >= FLAG_THRESHOLD).length;
    const totalSec = calls.reduce((s, c) => s + c.durationSec, 0);
    const hrs = Math.floor(totalSec / 3600), mins = Math.round((totalSec % 3600) / 60);
    let win = 0, bad = 0;
    calls.forEach((c) => { const a = c.frames.risk_score || []; win += a.length; bad += a.filter((v) => v >= RISK_BAD).length; });
    return { n, avgQ, flagged, callTimeBad: win ? bad / win : 0, dur: hrs > 0 ? `${hrs}h ${mins}m` : `${mins}m` };
  }, [calls, riskMetric]);

  const arrow = (key) => (sortKey === key
    ? <Icon name="chevron.down" size={11} color="var(--blue-40)" style={{ transform: sortDir === "asc" ? "rotate(180deg)" : "none", marginLeft: 4 }} />
    : null);
  const colHead = (label, key) => (
    <th onClick={key ? () => onSort(key) : undefined} style={{ padding: "16px 14px 12px", verticalAlign: "bottom", fontWeight: 500, fontSize: 11, letterSpacing: "0.05em", textTransform: "uppercase", fontFamily: "var(--font-mono)", color: key && sortKey === key ? "var(--text-primary)" : "var(--text-tertiary)", cursor: key ? "pointer" : "default", whiteSpace: "nowrap", userSelect: "none" }}>{label}{key && arrow(key)}</th>
  );

  return (
    <div data-screen-label="Post-call analysis" style={{ maxWidth: 1340, margin: "0 auto", padding: isMobile ? "24px 14px 56px" : "44px 32px 72px" }}>
      {/* header */}
      <div style={{ display: "flex", flexDirection: isMobile ? "column" : "row", alignItems: isMobile ? "stretch" : "flex-end", justifyContent: "space-between", gap: isMobile ? 18 : 24, marginBottom: 26 }}>
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12 }}>
            <Icon name="waveform.badge.magnifyingglass" size={17} color="var(--blue-40)" />
            <span className="aic-eyebrow">Audio Insight · post-call analysis</span>
          </div>
          <h1 style={{ fontFamily: "var(--font-display)", fontSize: isMobile ? 28 : 40, letterSpacing: "-0.025em", lineHeight: 1.08, margin: 0 }}>Call audio reliability</h1>
          <p style={{ fontSize: isMobile ? 14 : 15, color: "var(--text-secondary)", margin: "12px 0 0", maxWidth: "64ch", lineHeight: 1.55 }}>
            Will your Voice AI fail on this audio, and why? Every recording scored by the <span style={{ color: "var(--text-primary)" }}>Tyto Risk Score</span> and its six dimensions. <span style={{ color: "var(--text-tertiary)" }}>Lower is better.</span>
          </p>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 12, flex: "0 0 auto", flexWrap: "wrap" }}>
          {isCustom && <Badge tone="accent" dot>{restored ? "Restored data" : "Custom data"}</Badge>}
          {isCustom && onReset && (
            <Button variant="ghost" size="md" iconLeft="arrow.triangle.2.circlepath" onClick={onReset} style={{ fontWeight: 500, letterSpacing: 0 }}>Reset to demo</Button>
          )}
          <Button variant="secondary" size="md" iconLeft="plus" onClick={onLoadClick} style={{ fontWeight: 500, letterSpacing: 0 }}>Load data</Button>
        </div>
      </div>

      {/* aggregates */}
      <div style={{ display: "flex", flexWrap: "wrap", gap: 14, marginBottom: 26 }}>
        <StatTile label="Calls analyzed" value={agg.n} sub={`${agg.dur} of audio`} />
        <StatTile label="Avg risk score" value={fmtScore(agg.avgQ)} sub={qualityLabel(agg.avgQ)} accent={severityColor(Math.max(0.3, agg.avgQ))} />
        <StatTile label="Flagged for review" value={agg.flagged} unit={`/ ${agg.n}`} sub={`risk ≥ ${FLAG_THRESHOLD.toFixed(2)}`} accent={agg.flagged ? severityColor(0.7) : undefined} />
        <StatTile label="Call-time ≥ 0.60" value={fmtPct(agg.callTimeBad)} sub="windows in the Bad band" accent={agg.callTimeBad ? severityColor(0.8) : undefined} />
        <StatTile label="Model" value="Tyto" sub="Audio Insight · SDK" />
      </div>

      {/* toolbar */}
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 16, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "8px 13px", borderRadius: "var(--radius-md)", border: "1px solid var(--border-subtle)", background: "var(--surface-card)", width: 260 }}>
          <Icon name="magnifyingglass" size={15} color="var(--text-tertiary)" />
          <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search recordings…"
            style={{ flex: 1, border: "none", outline: "none", background: "transparent", color: "var(--text-primary)", fontFamily: "var(--font-sans)", fontSize: 14 }} />
        </div>
        <div style={{ flex: 1 }} />
        {driverFilter && (
          <Chip active onClick={() => setDriverFilter(null)} icon="xmark">Driver: {driverLabelOf(driverFilter)}</Chip>
        )}
        {/* risk metric: mean (call quality) vs p95 (worst moments) */}
        <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.04em", textTransform: "uppercase", color: "var(--text-tertiary)" }}>Risk</span>
          <div style={{ display: "flex", border: "1px solid var(--border-subtle)", borderRadius: "var(--radius-md)", overflow: "hidden" }}>
            {[["mean", "Mean"], ["p95", "p95"]].map(([m, lbl]) => (
              <button key={m} onClick={() => setRiskMetric(m)} style={{ padding: "7px 12px", border: "none", cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.03em", background: riskMetric === m ? "var(--surface-sunken)" : "transparent", color: riskMetric === m ? "var(--text-primary)" : "var(--text-tertiary)" }}>{lbl}</button>
            ))}
          </div>
        </div>
        <Chip active={flaggedOnly} onClick={() => setFlaggedOnly((v) => !v)} icon="exclamationmark.triangle.fill">Flagged only</Chip>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 12.5, color: "var(--text-tertiary)" }}>{view.length} of {calls.length}</span>
      </div>

      {/* table */}
      <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-subtle)", borderRadius: "var(--radius-lg)", overflow: "hidden" }}>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", minWidth: isMobile ? 0 : 1200 }}>
            <thead>
              <tr style={{ textAlign: "left" }}>
                <th onClick={() => onSort("file")} style={{ padding: "16px 16px 12px", verticalAlign: "bottom", fontWeight: 500, fontSize: 11, letterSpacing: "0.05em", textTransform: "uppercase", fontFamily: "var(--font-mono)", color: sortKey === "file" ? "var(--text-primary)" : "var(--text-tertiary)", cursor: "pointer", whiteSpace: "nowrap", userSelect: "none" }}>Recording {arrow("file")}</th>
                {!isMobile && colHead("Length", "duration")}
                {colHead("Review")}
                <HeadCell dim={DIMS[0]} sortKey={sortKey} sortDir={sortDir} onSort={onSort} />
                {colHead("% degraded", "fracDegraded")}
                {colHead("Driver")}
                {!isMobile && SUBDIMS.map((d) => <HeadCell key={d.key} dim={d} sortKey={sortKey} sortDir={sortDir} onSort={onSort} />)}
              </tr>
            </thead>
            <tbody>
              {view.map((c) => <Row key={c.id} call={c} onOpen={onOpen} riskMetric={riskMetric} driverFilter={driverFilter} onDriver={setDriverFilter} isMobile={isMobile} />)}
            </tbody>
          </table>
        </div>
        {view.length === 0 && (
          <div style={{ padding: "48px 0", textAlign: "center", color: "var(--text-tertiary)", fontSize: 14 }}>No recordings match your filters.</div>
        )}
      </div>
    </div>
  );
}

window.AITable = { Table };
})();
