/* Shared icons, FileIcon, GitPanel, FileTree */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---- minimal geometric icons ---- */
const Icon = {
  search: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><circle cx="7" cy="7" r="4.5" stroke="currentColor" strokeWidth="1.4"/><line x1="10.5" y1="10.5" x2="14" y2="14" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>),
  branch: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><circle cx="4" cy="3.5" r="1.8" stroke="currentColor" strokeWidth="1.3"/><circle cx="4" cy="12.5" r="1.8" stroke="currentColor" strokeWidth="1.3"/><circle cx="12" cy="5" r="1.8" stroke="currentColor" strokeWidth="1.3"/><path d="M4 5.3v5.4M5.8 5C9 5 10 6.2 10 9v0" stroke="currentColor" strokeWidth="1.3" fill="none"/></svg>),
  close: (p) => (<svg width="11" height="11" viewBox="0 0 12 12" fill="none" {...p}><path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>),
  copy: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><rect x="5" y="5" width="8" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.3"/><path d="M3 11V3a1 1 0 0 1 1-1h6" stroke="currentColor" strokeWidth="1.3" fill="none"/></svg>),
  terminal: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M3 4l3 3-3 3M8 11h5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  spark: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M8 1.5l1.6 4.9L14.5 8l-4.9 1.6L8 14.5 6.4 9.6 1.5 8l4.9-1.6L8 1.5z" stroke="currentColor" strokeWidth="1.1" fill="none" strokeLinejoin="round"/></svg>),
  file: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M4 2h5l3 3v9H4V2z" stroke="currentColor" strokeWidth="1.2" fill="none"/><path d="M9 2v3h3" stroke="currentColor" strokeWidth="1.2" fill="none"/></svg>),
  reveal: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M2 4.5h4l1.3 1.5H14V13H2V4.5z" stroke="currentColor" strokeWidth="1.2" fill="none"/></svg>),
  diff: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M4 2v8M4 12.5v1.5M2 4h4M2 8h4" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/><path d="M12 14V6M12 3.5V2M10 12h4M10 8h4" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/></svg>),
  plus: (p) => (<svg width="13" height="13" viewBox="0 0 14 14" fill="none" {...p}><path d="M7 2.5v9M2.5 7h9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>),
  minus: (p) => (<svg width="13" height="13" viewBox="0 0 14 14" fill="none" {...p}><path d="M2.5 7h9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/></svg>),
  check: (p) => (<svg width="13" height="13" viewBox="0 0 14 14" fill="none" {...p}><path d="M2.5 7.5l2.8 3L11.5 3.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  discard: (p) => (<svg width="13" height="13" viewBox="0 0 16 16" fill="none" {...p}><path d="M12.5 5.5A5 5 0 1 0 13 9" stroke="currentColor" strokeWidth="1.3" fill="none" strokeLinecap="round"/><path d="M12.5 2.5v3h-3" stroke="currentColor" strokeWidth="1.3" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>),
};

const Chevron = ({ open }) => (
  <svg width="9" height="9" viewBox="0 0 10 10" style={{ transform: open ? "rotate(90deg)" : "none", transition: "transform .12s" }}>
    <path d="M3.5 2l3.5 3-3.5 3" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round" />
  </svg>
);

const FolderIcon = ({ open }) => (
  <svg className="folder-ic" width="14" height="14" viewBox="0 0 16 16" fill="none">
    <path d={open ? "M1.5 4.5h4l1.2 1.4H14V13H2V4.5z" : "M1.5 4.5h4l1.2 1.4H14V13H1.5V4.5z"}
      fill={open ? "rgba(122,131,140,.18)" : "rgba(122,131,140,.12)"} stroke="currentColor" strokeWidth="1.1" />
  </svg>
);

function FileIcon({ path }) {
  const ic = HL.iconFor(path);
  return <span className="ficon" style={{ background: ic.c }}><span>{ic.t}</span></span>;
}

/* ============ Git / Source Control panel ============ */
function GitRow({ c, staged, activePath, onOpen, onContext, onToggleStage }) {
  const name = c.path.split("/").pop();
  const dir = c.path.split("/").slice(0, -1).join("/");
  return (
    <div className={"git-row" + (activePath === c.path ? " active" : "")}
      onClick={() => onOpen(c.path, { diff: true })}
      onContextMenu={(e) => onContext(e, { path: c.path, kind: "git", staged })}
      title={c.path}>
      <span className={"git-stat " + c.status}>{c.status}</span>
      <FileIcon path={c.path} />
      <span className={"git-name" + (c.deleted ? " del" : "")}>{name}</span>
      {dir && <span className="git-dir">{dir}/</span>}
      <button className="git-act" title={staged ? "Unstage changes" : "Stage changes"}
        onClick={(e) => { e.stopPropagation(); onToggleStage(c.path); }}>
        {staged ? Icon.minus({}) : Icon.plus({})}
      </button>
      <span className="git-delta">
        {c.add > 0 && <span className="a">+{c.add}</span>}
        {c.del > 0 && <span className="d">-{c.del}</span>}
      </span>
    </div>
  );
}

function GitPanel({ changes, staged, committed, commitMsg, setCommitMsg, onStage, onUnstage, onStageAll, onUnstageAll, onCommit, onOpen, onContext, activePath }) {
  const visible = changes.filter((c) => !committed.has(c.path));
  const stagedList = visible.filter((c) => staged.has(c.path));
  const changesList = visible.filter((c) => !staged.has(c.path));
  const totals = visible.reduce((a, c) => ({ add: a.add + c.add, del: a.del + c.del }), { add: 0, del: 0 });
  const canCommit = stagedList.length > 0 && commitMsg.trim().length > 0;

  return (
    <React.Fragment>
      <div className="phead">
        {Icon.branch({})}<span>Source Control</span>
        <span className="ct">{visible.length}</span>
      </div>

      <div className="commit-box">
        <textarea className="commit-input" rows={1} value={commitMsg} spellCheck={false}
          placeholder="Message (⌘↵ to commit)"
          onChange={(e) => setCommitMsg(e.target.value)}
          onKeyDown={(e) => { if ((e.metaKey || e.ctrlKey) && e.key === "Enter" && canCommit) { e.preventDefault(); onCommit(); } }} />
        <button className="commit-btn" disabled={!canCommit} onClick={onCommit}
          title={canCommit ? "Commit staged changes" : "Stage files and write a message to commit"}>
          {Icon.check({})}<span>Commit{stagedList.length ? " " + stagedList.length : ""}</span>
        </button>
      </div>

      <div className="git-body">
        {visible.length === 0 ? (
          <div className="git-empty">{Icon.check({ width: 20, height: 20 })}<span>No changes — working tree clean</span></div>
        ) : (
          <React.Fragment>
            <div className="git-group">
              Staged Changes <span className="gc">{stagedList.length}</span>
              {stagedList.length > 0 && <button className="grp-act" title="Unstage all" onClick={onUnstageAll}>{Icon.minus({})}</button>}
            </div>
            {stagedList.length > 0 ? stagedList.map((c) => (
              <GitRow key={c.path} c={c} staged={true} activePath={activePath}
                onOpen={onOpen} onContext={onContext} onToggleStage={onUnstage} />
            )) : (
              <div className="git-none">Nothing staged — use <span className="key">+</span> to stage a file</div>
            )}

            <div className="git-divider" />

            <div className="git-group">
              Changes <span className="gc">{changesList.length}</span>
              {changesList.length > 0 && <button className="grp-act" title="Stage all" onClick={onStageAll}>{Icon.plus({})}</button>}
            </div>
            {changesList.length > 0 ? changesList.map((c) => (
              <GitRow key={c.path} c={c} staged={false} activePath={activePath}
                onOpen={onOpen} onContext={onContext} onToggleStage={onStage} />
            )) : (
              <div className="git-none">All changes staged</div>
            )}
          </React.Fragment>
        )}
      </div>

      <div className="git-foot">
        <span className="branch-chip">{Icon.branch({})}<b>{PROJECT.branch}</b></span>
        <span style={{ marginLeft: "auto", fontFamily: "var(--mono)" }}>
          <span className="a" style={{ color: "var(--add)" }}>+{totals.add}</span>{" "}
          <span className="d" style={{ color: "var(--del)" }}>-{totals.del}</span>
        </span>
      </div>
    </React.Fragment>
  );
}

/* ============ File Tree ============ */
function TreeNode({ node, depth, openDirs, toggleDir, onOpen, onContext, activePath, changeMap, committed }) {
  const pad = 10 + depth * 13;
  if (node.type === "dir") {
    const isOpen = openDirs.has(node.path) || node.path === "";
    return (
      <React.Fragment>
        {node.path !== "" && (
          <div className="tree-row folder" style={{ paddingLeft: pad }}
            onClick={() => toggleDir(node.path)}
            onContextMenu={(e) => onContext(e, { path: node.path, kind: "dir" })}>
            <span className="tw"><Chevron open={isOpen} /></span>
            <FolderIcon open={isOpen} />
            <span className="tree-label">{node.name}</span>
          </div>
        )}
        {isOpen && node.children.map((c) => (
          <TreeNode key={c.path} node={c} depth={node.path === "" ? 0 : depth + 1}
            openDirs={openDirs} toggleDir={toggleDir} onOpen={onOpen}
            onContext={onContext} activePath={activePath} changeMap={changeMap} committed={committed} />
        ))}
      </React.Fragment>
    );
  }
  const status = committed && committed.has(node.path) ? null : changeMap[node.path];
  return (
    <div className={"tree-row" + (activePath === node.path ? " active" : "")}
      style={{ paddingLeft: pad + 2 }}
      onClick={() => onOpen(node.path)}
      onContextMenu={(e) => onContext(e, { path: node.path, kind: "file" })}
      title={node.path}>
      <span className="tw" />
      <FileIcon path={node.path} />
      <span className="tree-label" style={status === "D" ? { textDecoration: "line-through", color: "var(--fg-3)" } : null}>{node.name}</span>
      {status && <span className={"tree-badge " + status}>{status}</span>}
    </div>
  );
}

function FileTree({ tree, openDirs, toggleDir, onOpen, onContext, activePath, changeMap, committed }) {
  return (
    <React.Fragment>
      <div className="phead">
        <span>Explorer</span>
        <span style={{ marginLeft: "auto", color: "var(--fg-3)", textTransform: "none", letterSpacing: 0, fontFamily: "var(--mono)", fontSize: 10.5 }}>{tree.name}</span>
      </div>
      <div className="tree-body">
        <TreeNode node={tree} depth={0} openDirs={openDirs} toggleDir={toggleDir}
          onOpen={onOpen} onContext={onContext} activePath={activePath} changeMap={changeMap} committed={committed} />
      </div>
    </React.Fragment>
  );
}

Object.assign(window, { Icon, Chevron, FolderIcon, FileIcon, GitPanel, FileTree });
