/* ============================================================
   Lineage — shared UI primitives
   ============================================================ */
const { useState, useEffect, useRef, useMemo } = React;

/* ---- tiny icon set (simple geometric glyphs) ---- */
function Icon({ name, size = 16, stroke = 1.6, style }) {
  const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round",
    strokeLinejoin: "round", style };
  switch (name) {
    case "agent": // asterisk-spark
      return (<svg {...p}><path d="M12 3v18M3 12h18M5.6 5.6l12.8 12.8M18.4 5.6L5.6 18.4"/></svg>);
    case "commit":
      return (<svg {...p}><circle cx="12" cy="12" r="3.5"/><path d="M12 3v5.5M12 15.5V21"/></svg>);
    case "branch":
      return (<svg {...p}><circle cx="6" cy="5" r="2"/><circle cx="6" cy="19" r="2"/><circle cx="18" cy="7" r="2"/><path d="M6 7v10M18 9c0 4-6 3-6 8"/></svg>);
    case "pr":
      return (<svg {...p}><circle cx="6" cy="6" r="2"/><circle cx="6" cy="18" r="2"/><circle cx="18" cy="18" r="2"/><path d="M6 8v8M18 16V9a3 3 0 0 0-3-3h-3l2-2m0 4l-2-2"/></svg>);
    case "search":
      return (<svg {...p}><circle cx="11" cy="11" r="7"/><path d="M21 21l-4-4"/></svg>);
    case "read":
      return (<svg {...p}><path d="M4 5h10a2 2 0 0 1 2 2v12H6a2 2 0 0 1-2-2zM20 7v12"/></svg>);
    case "edit":
      return (<svg {...p}><path d="M4 20h4L18 10l-4-4L4 16zM14 6l4 4"/></svg>);
    case "run":
      return (<svg {...p}><path d="M5 4l14 8-14 8z"/></svg>);
    case "flag":
      return (<svg {...p}><path d="M5 21V4h11l-2 4 2 4H5"/></svg>);
    case "clock":
      return (<svg {...p}><circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/></svg>);
    case "coin":
      return (<svg {...p}><ellipse cx="12" cy="7" rx="7" ry="3"/><path d="M5 7v6c0 1.7 3.1 3 7 3s7-1.3 7-3V7M5 13c0 1.7 3.1 3 7 3s7-1.3 7-3"/></svg>);
    case "arrow":
      return (<svg {...p}><path d="M5 12h14M13 6l6 6-6 6"/></svg>);
    case "check":
      return (<svg {...p}><path d="M4 12l5 5L20 6"/></svg>);
    case "dot":
      return (<svg {...p}><circle cx="12" cy="12" r="4"/></svg>);
    case "spark":
      return (<svg {...p}><path d="M12 4l1.7 4.8L18.5 10l-4.8 1.7L12 16l-1.7-4.3L5.5 10l4.8-1.2z"/></svg>);
    case "chevron":
      return (<svg {...p}><path d="M9 6l6 6-6 6"/></svg>);
    case "link":
      return (<svg {...p}><path d="M9 12h6M10 8H8a4 4 0 0 0 0 8h2M14 8h2a4 4 0 0 1 0 8h-2"/></svg>);
    case "close":
      return (<svg {...p}><path d="M6 6l12 12M18 6L6 18"/></svg>);
    case "filter":
      return (<svg {...p}><path d="M4 5h16l-6 7v6l-4 2v-8z"/></svg>);
    case "graph":
      return (<svg {...p}><circle cx="6" cy="6" r="2"/><circle cx="6" cy="18" r="2"/><circle cx="17" cy="12" r="2"/><path d="M6 8v8M8 6h4a3 3 0 0 1 3 3M8 18h4a3 3 0 0 0 3-3"/></svg>);
    case "folder":
      return (<svg {...p}><path d="M4 7a2 2 0 0 1 2-2h3l2 2h7a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/></svg>);
    case "list":
      return (<svg {...p}><path d="M8 6h12M8 12h12M8 18h12M4 6h.01M4 12h.01M4 18h.01"/></svg>);
    default: return null;
  }
}
window.Icon = Icon;

/* ---- money / number formatting ---- */
const fmtUSD = (n, d = 2) => "$" + n.toLocaleString("en-US", { minimumFractionDigits: d, maximumFractionDigits: d });
const fmtUSD0 = (n) => "$" + Math.round(n).toLocaleString("en-US");
const fmtTok = (n) => n >= 1e6 ? (n / 1e6).toFixed(n >= 1e7 ? 0 : 1) + "M" : n >= 1e3 ? (n / 1e3).toFixed(0) + "K" : "" + n;
const fmtDur = (s) => s >= 60 ? Math.floor(s / 60) + "m " + (s % 60) + "s" : s + "s";
const fmtTime = (iso) => new Date(iso).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
const fmtDelta = (d) => (d >= 0 ? "+" : "−") + Math.round(Math.abs(d) * 100) + "%";
Object.assign(window, { fmtUSD, fmtUSD0, fmtTok, fmtDur, fmtTime, fmtDelta });

/* ---- Avatar (initials) ---- */
function Avatar({ name, color, size = 22 }) {
  const initials = name.split(" ").map(w => w[0]).slice(0, 2).join("");
  return (
    <span className="avatar" style={{
      width: size, height: size, background: color + "22", color: color,
      borderColor: color + "55", fontSize: size * 0.42,
    }}>{initials}</span>
  );
}
window.Avatar = Avatar;

/* ---- Repo badge (global scope facet) ---- */
function RepoBadge({ name, size = "sm" }) {
  const m = window.repoMeta(name);
  return (
    <span className={"repo-badge repo-badge-" + size}>
      <span className="repo-dot" style={{ background: m.color }} />
      <span className="repo-name mono">{name}</span>
    </span>
  );
}
window.RepoBadge = RepoBadge;

/* ---- Repo switcher (org → all repos / one repo) ---- */
function RepoSwitcher({ repo, setRepo }) {
  const [open, setOpen] = useState(false);
  const repos = window.LINEAGE_REPOS;
  const cur = repo === "all" ? null : window.repoMeta(repo);
  return (
    <div className="repo-switch">
      <button className="repo-switch-btn" onClick={() => setOpen(o => !o)}>
        {cur
          ? <React.Fragment><span className="repo-dot" style={{ background: cur.color }} /><span className="mono">{cur.name}</span></React.Fragment>
          : <React.Fragment><Icon name="graph" size={13} style={{ color: "var(--tx-3)" }} /><span>All repositories</span></React.Fragment>}
        <Icon name="chevron" size={13} style={{ opacity: 0.5, transform: open ? "rotate(90deg)" : "none", transition: "transform .15s" }} />
      </button>
      {open && (
        <React.Fragment>
          <div className="rs-scrim" onClick={() => setOpen(false)} />
          <div className="rs-menu">
            <button className={"rs-item" + (repo === "all" ? " on" : "")} onClick={() => { setRepo("all"); setOpen(false); }}>
              <Icon name="graph" size={14} style={{ color: "var(--tx-3)" }} />
              <span className="rs-item-name">All repositories</span>
              <span className="rs-item-meta mono">{window.LINEAGE_REPOS.length}</span>
            </button>
            <div className="rs-div" />
            {repos.map(rp => (
              <button key={rp.name} className={"rs-item" + (repo === rp.name ? " on" : "")} onClick={() => { setRepo(rp.name); setOpen(false); }}>
                <span className="repo-dot" style={{ background: rp.color }} />
                <span className="rs-item-name mono">{rp.name}</span>
                <span className="rs-item-desc">{rp.desc}</span>
              </button>
            ))}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}
window.RepoSwitcher = RepoSwitcher;

/* ====================  TOP BAR  ==================== */
function TopBar({ section, setSection, repo, setRepo }) {
  const nav = [
    { id: "history", label: "History", icon: "commit" },
    { id: "agents", label: "Agents", icon: "agent" },
    { id: "code", label: "Code", icon: "read" },
  ];
  return (
    <header className="topbar">
      <div className="topbar-inner">
        <div className="brand">
          <span className="brand-mark"><Icon name="branch" size={17} /></span>
          <span className="brand-name disp">Lineage</span>
        </div>
        <div className="org-crumb">
          <span className="crumb-org mono">{window.LINEAGE_ORG}</span>
          <RepoSwitcher repo={repo} setRepo={setRepo} />
        </div>
        <nav className="prime-nav">
          {nav.map(t => (
            <button key={t.id} className={"prime-tab" + (section === t.id ? " on" : "")} onClick={() => setSection(t.id)}>
              <Icon name={t.icon} size={15} />{t.label}
            </button>
          ))}
        </nav>
        <div className="topbar-search">
          <Icon name="search" size={15} style={{ color: "var(--tx-3)" }} />
          <input placeholder="Search code, agents, history…" />
          <kbd className="mono">/</kbd>
        </div>
      </div>
    </header>
  );
}
window.TopBar = TopBar;

/* ====================  METRICS STRIP (headline)  ==================== */
function Sparkline({ data, w = 92, h = 30 }) {
  const max = Math.max(...data), min = Math.min(...data);
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - 4 - ((v - min) / (max - min || 1)) * (h - 8);
    return [x, y];
  });
  const line = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L${w} ${h} L0 ${h} Z`;
  return (
    <svg width={w} height={h} className="spark">
      <defs>
        <linearGradient id="sparkg" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="var(--cost)" stopOpacity="0.35" />
          <stop offset="100%" stopColor="var(--cost)" stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill="url(#sparkg)" />
      <path d={line} fill="none" stroke="var(--cost)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.6" fill="var(--cost-2)" />
    </svg>
  );
}

function Metric({ label, value, sub, accent, delta, good, children }) {
  return (
    <div className="metric">
      <div className="metric-label">{label}</div>
      <div className="metric-row">
        <div className="metric-value disp" style={accent ? { color: accent } : null}>{value}</div>
        {children}
      </div>
      <div className="metric-sub">
        {delta != null && (
          <span className={"delta " + (good ? "up" : "down")}>{delta}</span>
        )}
        {sub && <span className="metric-subtext">{sub}</span>}
      </div>
    </div>
  );
}

function MetricsStrip() {
  const m = window.LINEAGE_METRICS;
  const agentPct = Math.round((m.agentAuthored / m.commits) * 100);
  return (
    <section className="metrics">
      <div className="metrics-head">
        <div className="metrics-title">
          <span className="eyebrow mono">COST → OUTPUT</span>
          <h2 className="disp">What the spend bought</h2>
        </div>
        <div className="period-pill mono">
          <Icon name="clock" size={13} />{m.period}
          <Icon name="chevron" size={13} style={{ opacity: 0.5 }} />
        </div>
      </div>
      <div className="metrics-grid">
        <Metric label="Token spend" value={fmtUSD0(m.spend)}
          delta={fmtDelta(m.spendDelta)} good={false} sub="vs prior 7d">
          <Sparkline data={m.spark} />
        </Metric>
        <div className="metric-div" />
        <Metric label="Agent runs" value={m.agentRuns.toLocaleString()}
          delta={fmtDelta(m.agentRunsDelta)} good={true} sub="completed" />
        <div className="metric-div" />
        <Metric label="Commits shipped" value={m.commits.toLocaleString()}
          sub={agentPct + "% agent-authored"}>
          <div className="authored-bar" title={agentPct + "% agent"}>
            <span style={{ width: agentPct + "%" }} />
          </div>
        </Metric>
        <div className="metric-div" />
        <Metric label="Cost / merged PR" value={fmtUSD(m.costPerPR)}
          delta={fmtDelta(m.costPerPRDelta)} good={true} sub={m.mergedPRs + " merged"} />
        <div className="metric-div" />
        <Metric label="Lines shipped" value={<span><span style={{ color: "var(--human-2)" }}>+{(m.linesAdd / 1000).toFixed(1)}k</span> <span style={{ color: "var(--tx-3)", fontWeight: 400 }}>/</span> <span style={{ color: "var(--danger)" }}>−{(m.linesDel / 1000).toFixed(1)}k</span></span>}
          sub={Math.round(m.acceptRate * 100) + "% agent accept rate"} />
      </div>
    </section>
  );
}
window.MetricsStrip = MetricsStrip;

/* ====================  FILTER BAR  ==================== */
function FilterBar({ filter, setFilter, counts, view, setView }) {
  const tabs = [
    { id: "all", label: "All activity", n: counts.all },
    { id: "agent", label: "Agent runs", n: counts.agent, dot: "var(--agent)" },
    { id: "commit", label: "Human commits", n: counts.commit, dot: "var(--human)" },
    { id: "pr", label: "Open PRs", n: counts.pr, dot: "var(--blue)" },
  ];
  return (
    <div className="filterbar">
      <div className="filter-tabs">
        {tabs.map(t => (
          <button key={t.id} className={"filter-tab" + (filter === t.id ? " on" : "")}
            onClick={() => setFilter(t.id)}>
            {t.dot && <span className="tab-dot" style={{ background: t.dot }} />}
            {t.label}
            <span className="tab-count mono">{t.n}</span>
          </button>
        ))}
      </div>
      <div className="view-toggle">
        <button className={view === "timeline" ? "on" : ""} onClick={() => setView("timeline")}>
          <Icon name="list" size={15} /> Timeline
        </button>
        <button className={view === "graph" ? "on" : ""} onClick={() => setView("graph")}>
          <Icon name="graph" size={15} /> Graph
        </button>
      </div>
    </div>
  );
}
window.FilterBar = FilterBar;
