/* === Marsirius × KKTCELL — Liquid glass dashboard === */

// v6 delta: F19 agents API, F24 meta, live audio blob, no fake upload steps.

const {
  fmt, SENTIMENT_TR, DAY_LABELS_TR,
  Pill, MarsiriusMark, MarsiriusWordmark, KKTCellMark, KKTCellWordmark, Spinner, CopyButton,
  VBarChart, MiniStat, Donut, CircleProgress,
  Transcript, MetricsTab, SignalsTab, CRMTab,
  LiveUploader,
  FeatureMatrix, FEATURES, computeFeatStates
} = window.MarsiriusUI;

const API = window.MarsiriusAPI;

/* ============================================
   FLOATING LEFT NAV RAIL component
   ============================================ */
function Rail({ active, onNav, alertCount = 0, kktcCount = 0, liveOpen = false }) {
  const items = [
  {
    key: "dashboard",
    label: "Ana Panel",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12 12 3l9 9" /><path d="M5 10v10a1 1 0 0 0 1 1h4v-7h4v7h4a1 1 0 0 0 1-1V10" /></svg>
  },
  {
    key: "calls",
    label: "Tüm Çağrılar",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" /></svg>
  },
  {
    key: "kktc",
    label: "KKTC Şivesi",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><line x1="2" y1="12" x2="22" y2="12" /><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></svg>,
    badge: kktcCount > 0 ? kktcCount : null
  },
  {
    key: "alerts",
    label: "Uyarılar",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /><line x1="12" y1="9" x2="12" y2="13" /><line x1="12" y1="17" x2="12.01" y2="17" /></svg>,
    dot: alertCount > 0
  },
  {
    key: "transcript",
    label: "Transcript",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /></svg>
  },
  {
    key: "signals",
    label: "Sinyaller",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12h2l3-9 4 18 3-12 2 6h6" /></svg>
  },
  {
    key: "metrics",
    label: "Metrikler",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3v18h18" /><path d="m19 9-5 5-4-4-3 3" /></svg>
  },
  {
    key: "crm",
    label: "CRM Payload",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" /><rect x="8" y="2" width="8" height="4" rx="1" /></svg>
  },
  {
    key: "live",
    label: "Canlı Analiz",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" /><path d="M19 10v2a7 7 0 0 1-14 0v-2" /><line x1="12" y1="19" x2="12" y2="23" /></svg>,
    dot: liveOpen
  },
  {
    key: "agents",
    label: "Temsilci Performansı",
    icon: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /><circle cx="8.5" cy="7" r="4" /><path d="M23 21v-2a4 4 0 0 0-3-3.87" /><path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg>
  }];


  return (
    <nav className="rail" aria-label="Navigasyon">
      <div className="rail-brand" title="Marsirius AI Labs">
        <img src="assets/marsirius-mark.png" alt="Marsirius" />
      </div>
      <div className="rail-sep" />
      {items.map((it, i) =>
      <React.Fragment key={it.key}>
          {(it.key === "alerts" || it.key === "live") && i > 0 && <div className="rail-sep" />}
          <button
          className={`rail-item ${active === it.key ? "is-active" : ""}`}
          onClick={() => onNav(it.key)}
          aria-label={it.label}>
          
            {it.icon}
            {it.dot && <span className="badge-dot" />}
            {it.badge != null && <span className="badge-count">{it.badge}</span>}
            <span className="rail-tip">{it.label}</span>
          </button>
        </React.Fragment>
      )}
      <div className="rail-sep" />
      <button
        className="rail-item"
        onClick={() => onNav("matrix")}
        aria-label="24 Özellik">
        
        <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0l2.4 7.6L22 10l-7.6 2.4L12 20l-2.4-7.6L2 10l7.6-2.4z" /></svg>
        <span className="rail-tip">24 Özellik</span>
      </button>
      <div className="rail-sep" />
      <div className="rail-partner" title="Turkcell Kuzey Kıbrıs" style={{ backgroundColor: "rgb(255, 195, 11)" }}>
        <img src="assets/kktcell-mark.png" alt="Turkcell KKTC" style={{ width: "36px", height: "36px", objectFit: "scale-down" }} />
      </div>
    </nav>);

}

/* ============================================
   AMBIENT — bg image + sparks
   ============================================ */
function Ambient() {
  const sparks = useMemo(() => Array.from({ length: 18 }).map((_, i) => ({
    top: 5 + Math.random() * 80,
    left: 3 + Math.random() * 94,
    delay: Math.random() * 4,
    size: 1 + Math.random() * 2,
    opacity: 0.3 + Math.random() * 0.6
  })), []);
  return (
    <>
      <div className="ambient" aria-hidden="true" />
      {sparks.map((s, i) =>
      <span
        key={i}
        className="spark"
        aria-hidden="true"
        style={{
          top: `${s.top}%`,
          left: `${s.left}%`,
          width: s.size,
          height: s.size,
          opacity: s.opacity,
          animationDelay: `${s.delay}s`
        }} />

      )}
    </>);

}

const { useState, useEffect, useRef, useMemo } = React;

/* ============================================
   HEADER
   ============================================ */
function ShellHead({ view, health, agentId, meta, onOpenCalls }) {
  const hybridLabel = (() => {
    if (!meta) return null;
    if (meta.deployment_model === "hybrid" || meta.stt_location && meta.llm_location) {
      const stt = meta.stt_location ? `STT ${meta.stt_location}` : null;
      const llm = meta.llm_location ? `LLM ${meta.llm_location}` : null;
      return ["Hybrid", stt, llm].filter(Boolean).join(" · ");
    }
    return null;
  })();
  return (
    <header className="shell-head">
      <div className="shell-head-left">
        <div className="brand-logo brand-logo-mars" title="Marsirius AI Labs">
          <MarsiriusWordmark height={72} />
        </div>
      </div>

      <div className="shell-head-center">
        <div className="page-eyebrow">VOICE INTELLIGENCE · v1.0</div>
        <div className="partner-row">
          <span className="partner-label" style={{ fontSize: "14px" }}>powered for</span>
          <div className="brand-logo brand-logo-kktc" title="Turkcell Kuzey Kıbrıs">
            <KKTCellWordmark height={32} />
          </div>
        </div>
      </div>

      <div className="shell-head-right">
        <div className="shell-status">
          <span className={`status-dot ${health === "ok" ? "" : health === "error" ? "is-err" : "is-off"}`} />
          {health === "ok" ? "Canlı" : health === "error" ? "Yok" : "Bağ..."}
        </div>
        <button className="icon-btn" onClick={onOpenCalls} title="Tüm çağrılar">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <rect x="3" y="4" width="18" height="18" rx="2" /><line x1="16" y1="2" x2="16" y2="6" /><line x1="8" y1="2" x2="8" y2="6" /><line x1="3" y1="10" x2="21" y2="10" />
          </svg>
        </button>
        <a className="icon-btn" href={window.MarsiriusAPI.apiUrl("/docs")} target="_blank" rel="noreferrer" title="API Docs">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M7 17 17 7" /><path d="M7 7h10v10" />
          </svg>
        </a>
        <div className="avatar-circle" title={agentId ? `Temsilci · ${agentId}` : "Temsilci yok"}>{agentId ? fmt.initials(agentId) : "—"}</div>
      </div>
    </header>);

}

/* ============================================
   ACTIVITY CARD — words per time bucket
   ============================================ */
function ActivityCard({ view }) {
  const lines = view.transcript && view.transcript.lines || [];
  const dur = view.metrics?.duration_s || Math.max(...lines.map((l) => l.end || 0), 60);
  const BUCKETS = 7;
  const bucketSec = dur / BUCKETS;
  const data = useMemo(() => {
    const buckets = Array(BUCKETS).fill(0);
    lines.forEach((l) => {
      if (l.start == null) return;
      const idx = Math.min(BUCKETS - 1, Math.floor(l.start / bucketSec));
      const words = (l.text || "").trim().split(/\s+/).filter(Boolean).length;
      buckets[idx] += words;
    });
    const max = Math.max(...buckets, 1);
    return buckets.map((v, i) => ({
      value: v,
      label: fmt.time(Math.round(i * bucketSec)),
      label2: `${Math.round(v / max * 100)}%`
    }));
  }, [lines, bucketSec]);

  const total = data.reduce((s, d) => s + d.value, 0);

  return (
    <div className="card">
      <div className="card-h">
        <div className="card-h-title">Konuşma Aktivitesi</div>
        <span className="pill is-slate no-dot mono" title="Kelime / zaman dilimi">
          {BUCKETS} dilim · {fmt.dur(dur)}
        </span>
      </div>
      <VBarChart data={data} />
      <div style={{ marginTop: 12, paddingTop: 12, borderTop: "1px solid var(--glass-border)", display: "flex", justifyContent: "space-between", fontSize: 11, color: "var(--muted)" }}>
        <span>Toplam <b style={{ color: "var(--ink)" }}>{total}</b> kelime · {lines.length} satır</span>
      </div>
    </div>);

}

/* ============================================
   MINI STATS COL (3 stacked stat cards)
   ============================================ */
function MiniStatsCol({ view }) {
  const ex = view.executive || {};
  const m = view.metrics || {};
  const sent = ex.sentiment || {};
  const lk = (sent.label || "").toLowerCase();
  const sentTone = lk.startsWith("pos") ? "green" : lk.startsWith("neg") ? "pink" : "violet";
  const sentConf = sent.score != null ? Math.round(Math.abs(sent.score) * 100) : null;

  return (
    <div className="mini-col">
      <MiniStat
        icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" /></svg>}
        iconTone={sentTone}
        value={SENTIMENT_TR[lk] || sent.label || "—"}
        unit={sentConf != null ? ` · ${sentConf}%` : ""}
        label="Duygu" />
      
      <MiniStat
        icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12h2l3-9 4 18 3-12 2 6h6" /></svg>}
        iconTone="cyan"
        value={m.snr_db != null ? m.snr_db.toFixed(0) : "—"}
        unit="dB"
        label="Sinyal/Gürültü" />
      
      <MiniStat
        icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 9" /></svg>}
        iconTone="violet"
        value={m.speech_rate_wpm != null ? Math.round(m.speech_rate_wpm) : "—"}
        unit="wpm"
        label="Konuşma hızı" />
      
    </div>);

}

/* ============================================
   OVERVIEW CARD — donut + legend
   ============================================ */
function OverviewCard({ view }) {
  const ex = view.executive || {};
  const m = view.metrics || {};
  const score = ex.quality_score;
  const scoreRule = ex.quality_score_rule;
  const scoreLLM = ex.quality_score_llm;
  const tone = score == null ? "muted" : score >= 80 ? "green" : score >= 60 ? "amber" : "red";

  // Build 3-segment donut: speech, agent silence, customer silence (real data)
  const speech = m.speech_s || 0;
  const agentS = m.agent_silence_s || 0;
  const custS = m.customer_silence_s || 0;
  const total = speech + agentS + custS || 1;

  const segments = [
  { key: "speech", label: "Konuşma", value: speech, color: "#22D3EE" },
  { key: "agent", label: "Temsilci s.", value: agentS, color: "#FBBF24" },
  { key: "cust", label: "Müşteri s.", value: custS, color: "#FF7B7B" }];


  return (
    <div className="card">
      <div className="card-h">
        <div className="card-h-title">Kalite & Akış</div>
        <span className="pill is-slate no-dot mono">
          {fmt.dur(view.metrics?.duration_s)} toplam
        </span>
      </div>
      <div className="donut-wrap">
        <Donut
          segments={segments}
          centerValue={score != null ? Math.round(score) : "—"}
          centerUnit={score != null ? "%" : ""}
          centerLabel="Kalite · LLM" />
        
        <div className="donut-legend">
          {segments.map((s) => {
            const pct = s.value / total * 100;
            return (
              <div key={s.key} className="donut-leg-row">
                <span className="donut-leg-k">
                  <span className="donut-leg-swatch" style={{ background: s.color, color: s.color }} />
                  {s.label}
                </span>
                <span className="donut-leg-v">{fmt.dur(s.value)}</span>
                <span className="donut-leg-d">{pct.toFixed(0)}%</span>
              </div>);

          })}
          {scoreRule != null &&
          <div className="donut-leg-row" style={{ paddingTop: 6, borderTop: "1px dashed var(--glass-border)" }}>
              <span className="donut-leg-k" style={{ color: "var(--muted)" }}>Kural skoru</span>
              <span className="donut-leg-v" style={{ color: "var(--ink-soft)" }}>{Math.round(scoreRule)}</span>
              <span className="donut-leg-d">/100</span>
            </div>
          }
          {scoreRule != null && scoreLLM != null && (
            <div style={{ fontSize: 10.5, color: "var(--muted)", marginTop: 4, letterSpacing: "0.02em" }}>
              Kural: <b style={{ color: "var(--ink-soft)" }}>{Math.round(scoreRule)}</b> · LLM: <b style={{ color: "var(--ink-soft)" }}>{Math.round(scoreLLM)}</b>
            </div>
          )}
        </div>
      </div>
    </div>);

}

/* ============================================
   CHALLENGES CARD — 24 feature compact (5 prominent)
   ============================================ */
function ChallengesCard({ view, meta, catalog, onOpenMatrix, agentReport, activeCatalog }) {
  const states = computeFeatStates(view, meta, catalog, { agentReport, activeCatalog });
  const onCount = states.filter((s) => s.has).length;

  // pick 5 most "interesting" features
  const featured = ["F08", "F20", "F16", "F13", "F15"];
  const items = featured.map((id) => states.find((s) => s.id === id)).filter(Boolean);

  return (
    <div className="card">
      <div className="card-h">
        <div className="card-h-title">24 Özellik</div>
        <button className="dropdown-pill" onClick={onOpenMatrix}>
          Tümünü göster
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6" /></svg>
        </button>
      </div>
      <div className="chal-list">
        {items.map((f) =>
        <div key={f.id} className="chal-row">
            <CircleProgress on={f.has} />
            <div>
              <div className="chal-row-label">{f.label}</div>
              <div className="chal-row-id">{f.id}</div>
            </div>
            <span className="chal-row-val">{f.has ? "Aktif" : "—"}</span>
            <Pill tone={f.has ? "green" : "slate"}>
              {f.has ? "Tamamlandı" : "Yok"}
            </Pill>
          </div>
        )}
      </div>
      <div className="chal-foot">
        <div className="chal-foot-summary">
          <div className="chal-foot-num">{onCount}<small>/ 24</small></div>
          <div className="chal-foot-label">Bu çağrıda aktif özellik</div>
        </div>
        <Pill tone={onCount >= 20 ? "green" : onCount >= 14 ? "amber" : "red"}>
          {onCount >= 20 ? "Tam kapsama" : onCount >= 14 ? "Kısmi" : "Az veri"}
        </Pill>
      </div>
    </div>);

}

/* ============================================
   RECENT CALLS card — week-strip
   ============================================ */
function RecentCallsCard({ catalog, activeId, onSelect }) {
  // sort with active in middle if possible; show up to 7
  const items = useMemo(() => {
    if (!catalog || catalog.length === 0) return [];
    const sorted = [...catalog];
    const idx = sorted.findIndex((c) => c.call_id === activeId);
    if (idx >= 0) {
      const start = Math.max(0, Math.min(sorted.length - 7, idx - 3));
      return sorted.slice(start, start + 7);
    }
    return sorted.slice(0, 7);
  }, [catalog, activeId]);

  const cur = catalog ? catalog.findIndex((c) => c.call_id === activeId) : -1;
  const prev = () => {if (cur > 0) onSelect(catalog[cur - 1].call_id);};
  const next = () => {if (cur >= 0 && cur < (catalog?.length || 0) - 1) onSelect(catalog[cur + 1].call_id);};
  const canPrev = cur > 0;
  const canNext = cur >= 0 && cur < (catalog?.length || 0) - 1;

  return (
    <div className="card">
      <div className="week-row">
        <div className="card-h-title">Demo Çağrılar <span style={{ color: "var(--muted)", fontWeight: 400, fontSize: 12, marginLeft: 6 }}>{cur + 1} / {catalog?.length || 0}</span></div>
        <div className="nav-arrows">
          <button className="nav-arrow" aria-label="Önceki çağrı" onClick={prev} disabled={!canPrev} style={{ opacity: canPrev ? 1 : 0.35, cursor: canPrev ? "pointer" : "not-allowed" }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6" /></svg>
          </button>
          <button className="nav-arrow" aria-label="Sonraki çağrı" onClick={next} disabled={!canNext} style={{ opacity: canNext ? 1 : 0.35, cursor: canNext ? "pointer" : "not-allowed" }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6" /></svg>
          </button>
        </div>
      </div>
      <div className="week-strip">
        {items.map((c, i) => {
          const isK = (c.accent || "").includes("kibris") || (c.call_id || "").includes("kibris") || (c.language || "").includes("kibris");
          const idx = (catalog || []).findIndex((x) => x.call_id === c.call_id) + 1;
          const active = c.call_id === activeId;
          return (
            <button
              key={c.call_id}
              className={`week-cell ${active ? "is-active" : ""}`}
              onClick={() => onSelect(c.call_id)}
              title={c.title || c.call_id}>
              
              <span className="week-cell-day">#{String(idx).padStart(2, "0")}</span>
              <span className="week-cell-num">
                {isK ? "KK" : (c.language || "tr").slice(0, 2).toUpperCase()}
              </span>
              {isK && <span className="week-cell-kktc" />}
            </button>);

        })}
      </div>
    </div>);

}

/* ============================================
   OUTPUT (action) card
   ============================================ */
function OutputCard({ view }) {
  const ex = view.executive || {};
  const action = ex.recommended_action || ex.action_required;
  const urgent = !!ex.churn_risk || !!ex.dissatisfaction;
  if (!action) return null;
  return (
    <div className="output-card">
      <div className="output-icon">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
          <path d="M12 0l2.4 7.6L22 10l-7.6 2.4L12 20l-2.4-7.6L2 10l7.6-2.4z" />
        </svg>
      </div>
      <div className="output-body">
        <div className="output-body-k">Önerilen aksiyon</div>
        <div className="output-body-text">{action}</div>
      </div>
      {urgent &&
      <Pill tone="red">Aciliyetli</Pill>
      }
    </div>);

}

/* ============================================
   SUMMARY CARD — executive.summary + intent
   ============================================ */
function SummaryCard({ view }) {
  const ex = view.executive || {};
  if (!ex.summary && !ex.intent) return null;
  return (
    <div className="card" style={{ minHeight: 0 }}>
      <div className="card-h">
        <div className="card-h-title">Çağrı Özeti</div>
        {ex.intent && (
          <span className="pill is-violet no-dot">{ex.intent}</span>
        )}
      </div>
      {ex.summary && (
        <p style={{ margin: 0, fontSize: 13.5, lineHeight: 1.55, color: "var(--ink-soft)", textWrap: "pretty" }}>
          {ex.summary}
        </p>
      )}
      {ex.dissatisfaction_reason && (
        <div style={{ marginTop: "auto", paddingTop: 10, borderTop: "1px dashed var(--glass-border)", fontSize: 12, color: "var(--ink-soft)" }}>
          <span style={{ color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.08em", fontSize: 10, fontWeight: 700 }}>Memnuniyetsizlik sebebi:</span>{" "}
          <span style={{ fontStyle: "italic" }}>{ex.dissatisfaction_reason}</span>
        </div>
      )}
    </div>);

}

/* ============================================
   SPEAKER BALANCE CARD — agent vs customer talk time
   ============================================ */
function SpeakerBalanceCard({ view }) {
  const m = view.metrics || {};
  const dur = m.duration_s || 0;
  const agentS = m.agent_silence_s || 0;
  const custS = m.customer_silence_s || 0;
  // talk time = total duration - own silence (rough approx)
  const agentTalk = Math.max(0, dur - agentS);
  const custTalk  = Math.max(0, dur - custS);
  const total = agentTalk + custTalk || 1;
  const agentPct = (agentTalk / total) * 100;
  const custPct  = (custTalk / total) * 100;

  if (!dur) return null;
  return (
    <div className="card" style={{ minHeight: 0 }}>
      <div className="card-h">
        <div className="card-h-title">Konuşmacı Dengesi</div>
        <span className="pill is-slate no-dot mono">{m.n_speakers != null ? `${m.n_speakers} konuşmacı` : "—"}</span>
      </div>
      <div className="balance-bar">
        <div className="balance-seg is-agent" style={{ width: `${agentPct}%` }}>
          <span className="balance-seg-pct">{Math.round(agentPct)}%</span>
        </div>
        <div className="balance-seg is-customer" style={{ width: `${custPct}%` }}>
          <span className="balance-seg-pct">{Math.round(custPct)}%</span>
        </div>
      </div>
      <div className="balance-legend">
        <div className="balance-leg">
          <span className="balance-leg-swatch is-agent" />
          <span>Temsilci</span>
          <b>{fmt.dur(agentTalk)}</b>
        </div>
        <div className="balance-leg">
          <span className="balance-leg-swatch is-customer" />
          <span>Müşteri</span>
          <b>{fmt.dur(custTalk)}</b>
        </div>
      </div>
      {m.overlap_detected != null && (
        <div className="balance-foot">
          <span>Üst üste konuşma</span>
          <Pill tone={m.overlap_detected ? "red" : "green"}>
            {m.overlap_detected ? "Tespit edildi" : "Yok"}
          </Pill>
        </div>
      )}
    </div>);

}

/* ============================================
   ALERT BANNER
   ============================================ */
function AlertBanner({ view }) {
  const ex = view.executive || {};
  const alerts = ex.alerts || [];
  const alertEvents = ex.alert_events || [];
  const alertCount = alerts.length + alertEvents.length;
  const hasAlerts = alertCount > 0;
  if (!hasAlerts && !ex.churn_risk) return null;
  return (
    <div className="alert-banner">
      <div className="alert-banner-icon">!</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="alert-banner-title">
          {hasAlerts ? `${alertCount} uyarı${ex.churn_risk ? " · churn riski" : ""}` : "Churn riski tespit edildi"}
        </div>
        <div className="alert-banner-sub">
          {hasAlerts ?
          <>
              {alerts.map((a, i) =>
            <span key={`a${i}`} className="alert-chip">
                  {typeof a === "string" ? a : a.category || a.label || a.type || a.code || "alert"}
                </span>
            )}
              {alertEvents.map((a, i) =>
            <span key={`e${i}`} className="alert-chip" title={a && a.context ? a.context : undefined}>
                  {typeof a === "string" ?
              a :
              a.category || a.label || a.type || a.code || "event"}
                  {a && a.keyword &&
              <span className="alert-chip-kw">"{a.keyword}"</span>
              }
                </span>
            )}
            </> :

          ex.dissatisfaction_reason ||
          "Müşteri kayıp olasılığı yüksek. Retention ekibine yönlendirin."
          }
        </div>
      </div>
    </div>);

}

/* ============================================
   DETAIL TABS (transcript / metrics / signals / crm / live)
   ============================================ */
function DetailTabs({ view, audioRef, currentTime, onSeek, meta, onAnalyzed, tab, onTabChange, liveAudioUrl }) {
  const lineCount = view.transcript && view.transcript.lines && view.transcript.lines.length || 0;
  const signalCount = view.signals ? Object.values(view.signals).filter((s) => s && s.present).length : 0;

  return (
    <div className="detail">
      <div className="tabs">
        <button className={`tab ${tab === "transcript" ? "is-active" : ""}`} onClick={() => onTabChange("transcript")}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
          </svg>
          Transcript
          {lineCount > 0 && <span className="tab-count">{lineCount}</span>}
        </button>
        <button className={`tab ${tab === "metrics" ? "is-active" : ""}`} onClick={() => onTabChange("metrics")}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            <path d="M3 3v18h18" /><path d="m19 9-5 5-4-4-3 3" />
          </svg>
          Metrikler
        </button>
        <button className={`tab ${tab === "signals" ? "is-active" : ""}`} onClick={() => onTabChange("signals")}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            <path d="M2 12h2l3-9 4 18 3-12 2 6h6" />
          </svg>
          Sinyaller
          {signalCount > 0 && <span className="tab-count">{signalCount}</span>}
        </button>
        <button className={`tab ${tab === "crm" ? "is-active" : ""}`} onClick={() => onTabChange("crm")}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
            <rect x="8" y="2" width="8" height="4" rx="1" />
          </svg>
          CRM
        </button>
        <button className={`tab ${tab === "live" ? "is-active" : ""}`} onClick={() => onTabChange("live")}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
            <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" /><path d="M19 10v2a7 7 0 0 1-14 0v-2" /><line x1="12" y1="19" x2="12" y2="23" />
          </svg>
          Canlı
        </button>
      </div>
      {tab === "transcript" && <Transcript view={view} audioRef={audioRef} currentTime={currentTime} onSeek={onSeek} liveAudioUrl={liveAudioUrl} />}
      {tab === "metrics" && <MetricsTab view={view} />}
      {tab === "signals" && <SignalsTab view={view} />}
      {tab === "crm" && <CRMTab view={view} />}
      {tab === "live" &&
      <LiveUploader
        enabled={meta ? !!meta.live_analyze_enabled : true}
        maxMb={meta ? meta.max_upload_mb : 25}
        onAnalyzed={onAnalyzed} />

      }
    </div>);

}

/* ============================================
   CALL LIST MODAL
   ============================================ */
function CallsModal({ open, onClose, catalog, activeId, onSelect, filter = null }) {
  const items = useMemo(() => {
    if (!catalog) return { kktc: [], other: [] };
    const k = [],o = [];
    catalog.forEach((c) => {
      const isK = (c.accent || "").includes("kibris") || (c.call_id || "").includes("kibris") || (c.language || "").includes("kibris");
      (isK ? k : o).push(c);
    });
    if (filter === "kktc") return { kktc: k, other: [] };
    return { kktc: k, other: o };
  }, [catalog, filter]);

  return (
    <>
      <div className={`modal-overlay ${open ? "is-open" : ""}`} onClick={onClose} />
      <aside className={`modal-panel ${open ? "is-open" : ""}`}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Tüm Çağrılar</div>
            <div className="modal-sub">{(catalog || []).length} demo çağrı</div>
          </div>
          <button className="modal-close" onClick={onClose}>×</button>
        </div>
        <div className="modal-body">
          {items.kktc.length > 0 &&
          <div style={{ padding: "8px 8px 4px", fontSize: 10.5, color: "var(--muted)", letterSpacing: "0.10em", textTransform: "uppercase", fontWeight: 700, display: "flex", alignItems: "center", gap: 6 }}>
              <KKTCellMark size={12} /> Kıbrıs Türkçesi · {items.kktc.length}
            </div>
          }
          <div className="call-list">
            {items.kktc.map((c, i) =>
            <button
              key={c.call_id}
              className={`call-item ${activeId === c.call_id ? "is-active" : ""}`}
              onClick={() => {onSelect(c.call_id);onClose();}}>
              
                <span className="call-item-num">{String(i + 1).padStart(2, "0")}</span>
                <div>
                  <div className="call-item-title">{c.title || c.call_id}</div>
                  <div className="call-item-meta">{c.call_id}{c.duration_s != null ? ` · ${fmt.dur(c.duration_s)}` : ""}</div>
                </div>
                <span className="call-item-tag">KKTC</span>
              </button>
            )}
          </div>
          {items.other.length > 0 &&
          <div style={{ padding: "16px 8px 4px", fontSize: 10.5, color: "var(--muted)", letterSpacing: "0.10em", textTransform: "uppercase", fontWeight: 700 }}>
              Diğer çağrılar · {items.other.length}
            </div>
          }
          <div className="call-list">
            {items.other.map((c, i) =>
            <button
              key={c.call_id}
              className={`call-item ${activeId === c.call_id ? "is-active" : ""}`}
              onClick={() => {onSelect(c.call_id);onClose();}}>
              
                <span className="call-item-num">{String(items.kktc.length + i + 1).padStart(2, "0")}</span>
                <div>
                  <div className="call-item-title">{c.title || c.call_id}</div>
                  <div className="call-item-meta">{c.call_id}{c.duration_s != null ? ` · ${fmt.dur(c.duration_s)}` : ""}</div>
                </div>
              </button>
            )}
          </div>
        </div>
      </aside>
    </>);

}

/* ============================================
   AGENT PERFORMANCE CARD — F19
   ============================================ */
function AgentsCard({ report, loading, error, onRetry, catalog, onSelectCall }) {
  return (
    <div className="card" id="agents-card">
      <div className="card-h">
        <div className="card-h-title">Temsilci Performansı</div>
        <span className="pill is-slate no-dot mono">
          {report ? `${report.n_agents ?? (report.agents?.length || 0)} temsilci` : "—"}
        </span>
      </div>
      {loading && (
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "18px 0", color: "var(--ink-soft)" }}>
          <Spinner size={16} /> /v1/reports/agents yükleniyor…
        </div>
      )}
      {error && !loading && (
        <div style={{ padding: "12px 0" }}>
          <div className="err" style={{ marginBottom: 10 }}>{error}</div>
          <button className="btn-ghost" onClick={onRetry}>Yeniden dene</button>
        </div>
      )}
      {!loading && !error && report && (
        <div className="agents-table">
          <div className="agents-row agents-row-h">
            <div>Temsilci</div>
            <div>Çağrı</div>
            <div>Kalite</div>
            <div>Retention %</div>
            <div>Ton</div>
            <div>Top kelimeler</div>
          </div>
          {(report.agents || []).map((a, i) => {
            const quality = a.quality_score_llm_mean ?? a.quality_score_mean;
            const ret = a.retention_offer_pct;
            const tone = (a.tone_profile || "").toLowerCase();
            const tonePill = tone.includes("optim") || tone.includes("iyimser") ? "green"
                           : tone.includes("pessim") || tone.includes("kötümser") ? "red"
                           : "slate";
            const topWords = (a.top_words || []).slice(0, 3);
            const match = catalog?.find((c) => c.agent_id === a.agent_id);
            const clickable = !!match;
            return (
              <div
                key={a.agent_id || i}
                className={`agents-row ${clickable ? "is-clickable" : ""}`}
                onClick={clickable ? () => onSelectCall(match.call_id) : undefined}
                title={clickable ? `Bu temsilcinin bir çağrısına git: ${match.call_id}` : undefined}
              >
                <div><b className="mono" style={{ color: "var(--ink)" }}>{a.agent_id || "—"}</b></div>
                <div className="mono">{a.call_count ?? "—"}</div>
                <div className="mono">{quality != null ? Math.round(quality) : "—"}</div>
                <div className="mono">{ret != null ? `${Math.round(ret * (ret <= 1 ? 100 : 1))}%` : "—"}</div>
                <div>
                  <Pill tone={tonePill}>
                    {tone.includes("optim") || tone.includes("iyimser") ? "İyimser"
                     : tone.includes("pessim") || tone.includes("kötümser") ? "Kötümser"
                     : tone.includes("neutral") || tone.includes("nötr") ? "Nötr"
                     : (a.tone_profile || "—")}
                  </Pill>
                </div>
                <div className="agents-words">
                  {topWords.length > 0 ? topWords.map((w, j) => (
                    <span key={j} className="agents-word-chip">
                      {typeof w === "string" ? w : (w.word || w.term || "—")}
                      {typeof w === "object" && w.count != null && <small>·{w.count}</small>}
                    </span>
                  )) : <span style={{ color: "var(--muted-2)", fontSize: 11 }}>—</span>}
                </div>
              </div>
            );
          })}
          {(!report.agents || report.agents.length === 0) && (
            <div style={{ padding: "14px 0", color: "var(--muted)", fontSize: 12.5, textAlign: "center" }}>
              Henüz temsilci verisi yok.
            </div>
          )}
        </div>
      )}
      <div className="agents-foot">
        <span className="mono" style={{ fontSize: 10.5 }}>GET /v1/reports/agents</span>
        <span style={{ color: "var(--violet-2)", fontSize: 10.5, fontWeight: 600 }}>F19</span>
      </div>
    </div>
  );
}

/* ============================================
   ROOT
   ============================================ */
function App() {
  const [health, setHealth] = useState("loading");
  const [meta, setMeta] = useState(null);
  const [catalog, setCatalog] = useState(null);
  const [view, setView] = useState(null);
  const [viewLoading, setViewLoading] = useState(false);
  const [viewError, setViewError] = useState(null);
  const [activeId, setActiveId] = useState(null);
  const [matrixOpen, setMatrixOpen] = useState(false);
  const [callsOpen, setCallsOpen] = useState(false);
  const [callsFilter, setCallsFilter] = useState(null);
  const [currentTime, setCurrentTime] = useState(0);
  const [railActive, setRailActive] = useState("dashboard");
  const [detailTab, setDetailTab] = useState("transcript");
  const [agentReport, setAgentReport] = useState(null);
  const [agentReportLoading, setAgentReportLoading] = useState(false);
  const [agentReportError, setAgentReportError] = useState(null);
  const [liveAudioUrl, setLiveAudioUrl] = useState(null);
  const audioRef = useRef(null);
  const shellRef = useRef(null);
  const alertRef = useRef(null);
  const detailRef = useRef(null);
  const agentsRef = useRef(null);

  useEffect(() => {
    let alive = true;
    (async () => {
      try {await API.getHealth();if (alive) setHealth("ok");}
      catch (e) {if (alive) setHealth("error");}
      try {const m = await API.getMeta();if (alive) setMeta(m);} catch (e) {}
      try {
        const c = await API.getCatalog();
        if (alive) {
          const items = Array.isArray(c) ? c : c.items || c.calls || c.demo || [];
          setCatalog(items);
        }
      } catch (e) {if (alive) setCatalog([]);}
      // Agent performance report (F19)
      if (alive) {
        setAgentReportLoading(true);
        try {
          const r = await API.getAgentReport();
          if (alive) { setAgentReport(r); setAgentReportError(null); }
        } catch (e) {
          if (alive) setAgentReportError(e.message || String(e));
        } finally {
          if (alive) setAgentReportLoading(false);
        }
      }
    })();
    return () => {alive = false;};
  }, []);

  const reloadAgents = async () => {
    setAgentReportLoading(true);
    setAgentReportError(null);
    try { setAgentReport(await API.getAgentReport()); }
    catch (e) { setAgentReportError(e.message || String(e)); }
    finally { setAgentReportLoading(false); }
  };

  useEffect(() => {
    if (catalog && catalog.length && !activeId) {
      const kktc = catalog.find(
        (c) => (c.call_id || "").includes("kibris") || (c.accent || "").includes("kibris")
      );
      const first = kktc || catalog[0];
      if (first) selectCall(first.call_id);
    }
    // eslint-disable-next-line
  }, [catalog]);

  useEffect(() => {setCurrentTime(0);setDetailTab("transcript");setRailActive("dashboard");}, [view && view.call_id]);
  useEffect(() => {
    if (["transcript", "metrics", "signals", "crm", "live"].includes(detailTab)) {
      setRailActive(detailTab);
    }
  }, [detailTab]);
  useEffect(() => {
    const a = audioRef.current;
    if (!a) return;
    const onT = () => setCurrentTime(a.currentTime);
    a.addEventListener("timeupdate", onT);
    return () => a.removeEventListener("timeupdate", onT);
  }, [view && view.call_id]);

  const selectCall = async (callId) => {
    setActiveId(callId);
    setViewLoading(true);
    setViewError(null);
    if (liveAudioUrl) {
      try { URL.revokeObjectURL(liveAudioUrl); } catch (e) {}
      setLiveAudioUrl(null);
    }
    try {const v = await API.getDemoCall(callId);setView(v);}
    catch (e) {setViewError(e.message || String(e));setView(null);} finally
    {setViewLoading(false);}
  };

  const onSeek = (s) => {
    const a = audioRef.current;
    if (a) {a.currentTime = s;a.play && a.play().catch(() => {});}
  };

  const onAnalyzed = (res, file) => {
    setView(res);
    setActiveId(res.call_id || null);
    setViewError(null);
    if (liveAudioUrl) { try { URL.revokeObjectURL(liveAudioUrl); } catch (e) {} }
    if (file) {
      setLiveAudioUrl(URL.createObjectURL(file));
    } else {
      setLiveAudioUrl(null);
    }
  };

  const activeCatalog = useMemo(
    () => (catalog || []).find((c) => c.call_id === activeId) || null,
    [catalog, activeId]
  );

  const activeFeats = useMemo(
    () => computeFeatStates(view, meta, catalog, { agentReport, activeCatalog }).filter((s) => s.has).length,
    [view, catalog, meta, agentReport, activeCatalog]
  );

  const kktcCount = useMemo(() => {
    if (!catalog) return 0;
    return catalog.filter((c) =>
    (c.accent || "").includes("kibris") || (c.call_id || "").includes("kibris") || (c.language || "").includes("kibris")
    ).length;
  }, [catalog]);

  const alertCount = useMemo(() => {
    if (!view || !view.executive) return 0;
    return (view.executive.alerts?.length || 0) + (view.executive.alert_events?.length || 0);
  }, [view]);

  const scrollTo = (ref) => {
    if (ref && ref.current) {
      const top = ref.current.getBoundingClientRect().top + window.scrollY - 24;
      window.scrollTo({ top, behavior: "smooth" });
    }
  };

  const handleRail = (key) => {
    setRailActive(key);
    if (key === "dashboard") {
      window.scrollTo({ top: 0, behavior: "smooth" });
    } else if (key === "calls") {
      setCallsFilter(null);
      setCallsOpen(true);
    } else if (key === "kktc") {
      setCallsFilter("kktc");
      setCallsOpen(true);
    } else if (key === "alerts") {
      if (alertRef.current) scrollTo(alertRef);else
      {setDetailTab("signals");scrollTo(detailRef);}
    } else if (["transcript", "metrics", "signals", "crm", "live"].includes(key)) {
      setDetailTab(key);
      scrollTo(detailRef);
    } else if (key === "matrix") {
      setMatrixOpen(true);
    }
  };

  return (
    <>
      <Ambient />
      <div className="app" style={{ opacity: "1" }}>
        <div className="shell" style={{ opacity: "0.8" }}>
          <ShellHead
            view={view}
            health={health}
            agentId={view?.agent_id}
            meta={meta}
            onOpenCalls={() => setCallsOpen(true)} />
          

          {viewLoading &&
          <div className="center-loading">
              <Spinner size={28} />
              <div className="center-loading-title">Çağrı yükleniyor</div>
              <div className="center-loading-sub">Marsirius Voice API'ye bağlanılıyor</div>
            </div>
          }

          {viewError && !viewLoading &&
          <div className="center-error">
              <div className="err-title">Çağrı yüklenemedi</div>
              <div className="err-msg">{viewError}</div>
              <button className="btn-primary" onClick={() => activeId && selectCall(activeId)}>Yeniden dene</button>
            </div>
          }

          {!view && !viewLoading && !viewError &&
          <div className="empty-state">
              <div className="empty-mark">
                <div className="brand-logo-chip" style={{ padding: "18px 26px" }}>
                  <MarsiriusWordmark height={48} />
                </div>
              </div>
              <div className="empty-title">Bir çağrı seç</div>
              <div className="empty-sub">Tüm çağrılar düğmesinden bir demo çağrı seçebilir veya canlı analiz için ses dosyası yükleyebilirsiniz.</div>
              <div style={{ marginTop: 14, display: "inline-flex", alignItems: "center", gap: 10, opacity: 0.85 }}>
                <span style={{ fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-soft)", fontWeight: 600 }}>powered for</span>
                <div className="brand-logo-chip is-small"><KKTCellWordmark height={16} /></div>
              </div>
            </div>
          }

          {view && !viewLoading && !viewError &&
          <>
              <div className="grid-top">
                <ActivityCard view={view} />
                <MiniStatsCol view={view} />
                <OverviewCard view={view} />
              </div>
              <div className="grid-mid">
                <ChallengesCard
                view={view}
                meta={meta}
                catalog={catalog}
                onOpenMatrix={() => setMatrixOpen(true)}
                agentReport={agentReport}
                activeCatalog={activeCatalog} />
              
                <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                  <RecentCallsCard
                  catalog={catalog}
                  activeId={activeId}
                  onSelect={selectCall} />
                
                  <OutputCard view={view} />
                  <SummaryCard view={view} />
                  <SpeakerBalanceCard view={view} />
                </div>
              </div>
              <div ref={agentsRef}>
                <AgentsCard
                  report={agentReport}
                  loading={agentReportLoading}
                  error={agentReportError}
                  onRetry={reloadAgents}
                  catalog={catalog}
                  onSelectCall={selectCall} />
              </div>
              <div ref={alertRef}>
                <AlertBanner view={view} />
              </div>
              <div ref={detailRef}>
                <DetailTabs
                view={view}
                audioRef={audioRef}
                currentTime={currentTime}
                onSeek={onSeek}
                meta={meta}
                onAnalyzed={onAnalyzed}
                tab={detailTab}
                onTabChange={setDetailTab}
                liveAudioUrl={liveAudioUrl} />
              
              </div>
            </>
          }
        </div>
      </div>

      <Rail
        active={railActive}
        onNav={handleRail}
        alertCount={alertCount}
        kktcCount={kktcCount}
        liveOpen={meta && meta.live_analyze_enabled} />
      

      <CallsModal
        open={callsOpen}
        onClose={() => {setCallsOpen(false);setCallsFilter(null);}}
        catalog={catalog}
        activeId={activeId}
        onSelect={selectCall}
        filter={callsFilter} />
      

      <FeatureMatrix
        view={view}
        meta={meta}
        catalog={catalog}
        open={matrixOpen}
        onClose={() => setMatrixOpen(false)}
        agentReport={agentReport}
        activeCatalog={activeCatalog} />
      
    </>);

}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);