/* ============================================================
   Lineage — Code view (the reimagined git browser)
   git blame -> git lineage: every block traces to the run or
   commit that authored it, and (for agents) the intent behind it.
   ============================================================ */

/* ---- minimal syntax highlighter ---- */
function highlight(line) {
  const re = /(\/\/[^\n]*)|("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')|\b(use|pub|struct|impl|fn|let|mut|async|await|while|match|return|self|Self|export|class|const|private|new|if|else|crate|for|of|import|from|type|interface|in|throw)\b|\b([A-Z][A-Za-z0-9_]*)\b|(\b\d[\d_]*\b)/g;
  const out = []; let last = 0, m, key = 0;
  while ((m = re.exec(line))) {
    if (m.index > last) out.push(<span key={key++}>{line.slice(last, m.index)}</span>);
    const cls = m[1] ? "hl-com" : m[2] ? "hl-str" : m[3] ? "hl-kw" : m[4] ? "hl-typ" : "hl-num";
    out.push(<span key={key++} className={cls}>{m[0]}</span>);
    last = m.index + m[0].length;
  }
  if (last < line.length) out.push(<span key={key++}>{line.slice(last)}</span>);
  return out.length ? out : [<span key="e">{"\u00A0"}</span>];
}

/* ---- who authored this ---- */
function Authored({ by, who, color, age, compact }) {
  if (by === "agent") {
    return (
      <span className="auth auth-agent">
        <Icon name="spark" size={12} style={{ color: "var(--agent)" }} />
        <span className="auth-name">{who}</span>
        {age && !compact && <span className="auth-age mono">{age}</span>}
      </span>
    );
  }
  return (
    <span className="auth auth-human">
      <Avatar name={who} color={color || "#8b8f9a"} size={16} />
      <span className="auth-name">{who}</span>
      {age && !compact && <span className="auth-age mono">{age}</span>}
    </span>
  );
}

/* ---- file / dir glyph ---- */
function FileGlyph({ type, lang }) {
  if (type === "dir") return <Icon name="folder" size={15} style={{ color: "var(--blue)" }} />;
  const code = ({ rust: "rs", ts: "ts", md: "md", toml: "to", json: "{}" })[lang] || (lang || "·").slice(0, 2);
  const c = lang === "rust" ? "#dea584" : lang === "ts" ? "#6aa6ff" : lang === "md" ? "var(--tx-3)" : "var(--tx-2)";
  return <span className="file-glyph" style={{ borderColor: c, color: c }}>{code}</span>;
}

/* ====================  LEFT TREE  ==================== */
function TreeNode({ node, depth, openFile, current, path }) {
  const [open, setOpen] = useState(depth < 1);
  const isDir = node.type === "dir";
  const full = path ? path + "/" + node.name : node.name;
  return (
    <div className="tn">
      <button
        className={"tn-row" + (current === node.file ? " on" : "")}
        style={{ paddingLeft: 10 + depth * 14 }}
        onClick={() => isDir ? setOpen(o => !o) : (node.file && openFile(node.file))}>
        {isDir && <Icon name="chevron" size={12} style={{ transform: open ? "rotate(90deg)" : "none", color: "var(--tx-3)", flex: "none" }} />}
        {!isDir && <span style={{ width: 12, flex: "none" }} />}
        <FileGlyph type={node.type} lang={node.lang} />
        <span className="tn-name">{node.name}</span>
        {node.by === "agent" && <span className="tn-agentdot" title={"last by " + node.who} />}
      </button>
      {isDir && open && node.children && (
        <div className="tn-children">
          {node.children.map(c => (
            <TreeNode key={c.name} node={c} depth={depth + 1} openFile={openFile} current={current} path={full} />
          ))}
        </div>
      )}
    </div>
  );
}

/* ====================  FILE LIST (dir contents)  ==================== */
function FileList({ nodes, dirPath, openFile, navDir }) {
  // dirs first, then files
  const sorted = [...nodes].sort((a, b) => (a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1));
  return (
    <div className="filelist">
      <div className="fl-head mono">
        <span className="fl-h-name">{dirPath.length ? dirPath[dirPath.length - 1] : "atlas"}</span>
        <span className="fl-h-last">Last change</span>
        <span className="fl-h-age">When</span>
      </div>
      {sorted.map(n => (
        <button key={n.name} className="fl-row" onClick={() => n.type === "dir" ? navDir(n.name) : (n.file && openFile(n.file))}>
          <span className="fl-name">
            <FileGlyph type={n.type} lang={n.lang} />
            <span className={n.type === "dir" ? "fl-n-dir" : "fl-n-file"}>{n.name}</span>
          </span>
          <span className="fl-msg">
            <Authored by={n.by} who={n.who} color={n.color} compact />
            <span className="fl-msg-text">{n.msg}</span>
          </span>
          <span className="fl-age mono">{n.age}</span>
        </button>
      ))}
    </div>
  );
}

/* ====================  ABOUT RAIL  ==================== */
function AboutRail() {
  const r = window.LINEAGE_REPO;
  const a = window.LINEAGE_AUTHORSHIP;
  return (
    <aside className="about">
      <div className="about-block">
        <h3 className="about-h">About</h3>
        <p className="about-desc">{r.desc}</p>
      </div>
      <div className="about-block">
        <div className="about-label">Authorship</div>
        <div className="authorship-bar">
          <span className="ab-agent" style={{ width: a.agentPct + "%" }} />
          <span className="ab-human" style={{ width: (100 - a.agentPct) + "%" }} />
        </div>
        <div className="authorship-legend mono">
          <span><span className="lg-dot" style={{ background: "var(--agent)" }} />{a.agentPct}% agent</span>
          <span><span className="lg-dot" style={{ background: "var(--human)" }} />{100 - a.agentPct}% human</span>
        </div>
      </div>
      <div className="about-block">
        <div className="about-label">Languages</div>
        <div className="lang-bar">
          {a.langs.map(l => <span key={l.name} style={{ width: l.pct + "%", background: l.color }} title={l.name} />)}
        </div>
        <div className="lang-legend mono">
          {a.langs.map(l => <span key={l.name}><span className="lg-dot" style={{ background: l.color }} />{l.name} {l.pct}%</span>)}
        </div>
      </div>
    </aside>
  );
}

/* ====================  CODE FILE (blame)  ==================== */
function CodeFile({ path, onSelectRun }) {
  const [blameOn, setBlameOn] = useState(true);
  const f = window.LINEAGE_FILES[path];
  const name = path.split("/").pop();
  const parts = path.split("/");

  if (!f) {
    return (
      <div className="codefile">
        <div className="cf-empty">
          <Icon name="read" size={22} style={{ color: "var(--tx-3)" }} />
          <div><strong>{name}</strong> isn’t indexed in this demo.</div>
          <div className="cf-empty-sub">Pick <span className="mono">pipeline.rs</span> or <span className="mono">cache.ts</span> to see line-level lineage.</div>
        </div>
      </div>
    );
  }

  const total = f.blame.reduce((n, b) => n + b.code.length, 0);
  const agentLines = f.blame.filter(b => b.kind === "agent").reduce((n, b) => n + b.code.length, 0);
  const agentPct = Math.round((agentLines / total) * 100);
  let ln = 0;

  return (
    <div className="codefile">
      <div className="cf-bar">
        <div className="cf-path mono">
          {parts.map((p, i) => (
            <span key={i}>{i > 0 && <span className="cf-sep">/</span>}<span className={i === parts.length - 1 ? "cf-p-last" : "cf-p"}>{p}</span></span>
          ))}
        </div>
        <div className="cf-meta mono">
          <span>{total} lines</span>
          <span className="cf-dot">·</span>
          <span className="cf-agentpct"><Icon name="spark" size={11} style={{ color: "var(--agent)" }} />{agentPct}% agent</span>
        </div>
        <button className={"blame-toggle" + (blameOn ? " on" : "")} onClick={() => setBlameOn(b => !b)}>
          <Icon name="filter" size={13} /> Lineage
        </button>
      </div>

      <div className={"cf-code" + (blameOn ? " blame" : "")}>
        {f.blame.map((b, bi) => {
          const start = ln + 1;
          const lines = b.code.map((c) => { ln += 1; return { n: ln, c }; });
          const isAgent = b.kind === "agent";
          return (
            <div key={bi}
              className={"blk kind-" + b.kind + (isAgent && b.evId ? " clickable" : "")}
              onClick={() => isAgent && b.evId && onSelectRun(b.evId)}>
              {blameOn && (
                <div className="blk-gutter">
                  <div className="blk-auth">
                    <Authored by={b.kind} who={b.who} color={b.color} />
                  </div>
                  <div className="blk-sub mono">
                    {isAgent
                      ? <span className="blk-intent" title={b.msg}>{b.msg}</span>
                      : <span className="blk-hash">{b.hash}</span>}
                  </div>
                  {isAgent && b.evId && <span className="blk-open mono">view run →</span>}
                </div>
              )}
              <div className="blk-code">
                {lines.map(l => (
                  <div className="cl" key={l.n}>
                    <span className="cl-n mono">{l.n}</span>
                    <code className="cl-t mono">{highlight(l.c)}</code>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ====================  REPO VIEW  ==================== */
function RepoView({ onSelectRun }) {
  const [dirPath, setDirPath] = useState([]); // for file list
  const [filePath, setFilePath] = useState(null);

  const nodesAt = (pathArr) => {
    let nodes = window.LINEAGE_TREE;
    for (const seg of pathArr) {
      const dir = nodes.find(n => n.name === seg && n.type === "dir");
      nodes = dir && dir.children ? dir.children : [];
    }
    return nodes;
  };

  const openFile = (p) => setFilePath(p);
  const navDir = (name) => { setDirPath(d => [...d, name]); setFilePath(null); };
  const crumbTo = (i) => { setDirPath(d => d.slice(0, i)); setFilePath(null); };

  return (
    <div className="code-layout">
      <div className="tree-panel">
        <div className="tree-head mono">
          <Icon name="branch" size={13} /> {window.LINEAGE_REPO.branch}
        </div>
        <div className="tree-scroll">
          {window.LINEAGE_TREE.map(n => (
            <TreeNode key={n.name} node={n} depth={0} openFile={openFile} current={filePath} path="" />
          ))}
        </div>
      </div>

      <div className="code-main">
        <div className="path-bar">
          <button className="crumb-seg" onClick={() => { setDirPath([]); setFilePath(null); }}>{window.LINEAGE_REPO.name}</button>
          {dirPath.map((seg, i) => (
            <span key={i}><span className="crumb-sl">/</span><button className="crumb-seg" onClick={() => crumbTo(i + 1)}>{seg}</button></span>
          ))}
          {filePath && filePath.replace(dirPath.join("/") ? dirPath.join("/") + "/" : "", "").split("/").map((seg, i, arr) => (
            <span key={"f" + i}><span className="crumb-sl">/</span><span className="crumb-file">{seg}</span></span>
          ))}
        </div>

        {filePath ? (
          <CodeFile path={filePath} onSelectRun={onSelectRun} />
        ) : (
          <div className="browse-grid">
            <FileList nodes={nodesAt(dirPath)} dirPath={dirPath} openFile={openFile} navDir={navDir} />
            {dirPath.length === 0 && <AboutRail />}
          </div>
        )}
      </div>
    </div>
  );
}
window.RepoView = RepoView;
