import type { FC } from "hono/jsx";
import { html } from "hono/html";
import type { GitCommit, GitTreeEntry, GitDiffFile } from "../git/repository";
import type { Repository } from "../db/schema";
import { parseDiff, pairLines } from "../lib/diff";
import type { DiffLine, ParsedFile, SplitRow } from "../lib/diff";

/**
 * Describes the most recent push to a repo, used by RepoHeader to render
 * the Push Watch discoverability indicator.
 *
 * - ageMs < 5 min  \u2192 pulsing red "\u25cf Live" badge
 * - ageMs < 24 hr  \u2192 dimmer "\u25cb Watch" link
 * - otherwise      \u2192 nothing shown
 */
export interface RecentPush {
  sha: string;
  ageMs: number;
}

export const RepoHeader: FC<{
  owner: string;
  repo: string;
  starCount?: number;
  starred?: boolean;
  forkCount?: number;
  currentUser?: string | null;
  forkedFrom?: string | null;
  archived?: boolean;
  isTemplate?: boolean;
  /** Most recent push info for Push Watch discoverability indicator. */
  recentPush?: RecentPush | null;
  /** 0-100 health score badge rendered after the repo name. Optional — omit to hide. */
  healthScore?: number;
}> = ({
  owner,
  repo,
  starCount,
  starred,
  forkCount,
  currentUser,
  forkedFrom,
  archived,
  isTemplate,
  recentPush,
  healthScore,
}) => {
  const FIVE_MIN = 5 * 60 * 1000;
  const TWENTY_FOUR_HR = 24 * 60 * 60 * 1000;
  const isLive = recentPush != null && recentPush.ageMs < FIVE_MIN;
  const isRecent = recentPush != null && recentPush.ageMs < TWENTY_FOUR_HR;

  const healthColor =
    healthScore === undefined ? null :
    healthScore >= 80 ? "#34d399" :
    healthScore >= 50 ? "#facc15" :
    "#f87171";

  return (
    <div class="repo-header">
      <div>
        <div class="repo-header-title">
          <a href={`/${owner}`} class="owner">
            {owner}
          </a>
          <span class="separator">/</span>
          <a href={`/${owner}/${repo}`} class="name">
            {repo}
          </a>
          {archived && (
            <span
              class="repo-header-pill repo-header-pill-archived"
              title="Read-only: pushes and new issues/PRs disabled"
            >
              Archived
            </span>
          )}
          {isTemplate && (
            <span
              class="repo-header-pill repo-header-pill-template"
              title="This repository can be used as a template"
            >
              Template
            </span>
          )}
          {healthScore !== undefined && healthColor && (
            <a
              href={`/${owner}/${repo}/health`}
              title={`Repository health score: ${healthScore}/100 — click for breakdown`}
              style={`display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:9999px;font-size:11px;font-weight:700;text-decoration:none;color:${healthColor};background:${healthColor}22;border:1px solid ${healthColor}44;`}
            >
              &#x2665; Health {healthScore}
            </a>
          )}
          {isLive && recentPush && (
            <a
              href={`/${owner}/${repo}/push/${recentPush.sha}`}
              class="repo-header-live-badge repo-header-live-badge--live"
              title="Push in progress \u2014 watch live gate + deploy status"
              aria-label="Live push \u2014 click to watch status"
            >
              <span class="repo-header-live-dot" aria-hidden="true">{"\u25cf"}</span>
              Live
            </a>
          )}
          {!isLive && isRecent && recentPush && (
            <a
              href={`/${owner}/${repo}/push/${recentPush.sha}`}
              class="repo-header-live-badge repo-header-live-badge--recent"
              title="Watch the most recent push's gate + deploy results"
              aria-label="Watch most recent push"
            >
              <span aria-hidden="true">{"\u25cb"}</span>
              Watch
            </a>
          )}
        </div>
        {forkedFrom && (
          <div class="repo-header-fork">
            forked from <a href={`/${forkedFrom}`}>{forkedFrom}</a>
          </div>
        )}
      </div>
      <div class="repo-header-actions">
        {currentUser && currentUser !== owner && (
          <form method="post" action={`/${owner}/${repo}/fork`} style="display:inline">
            <button type="submit" class="star-btn">
              {"\u2442"} Fork {forkCount !== undefined && forkCount > 0 ? forkCount : ""}
            </button>
          </form>
        )}
        {starCount !== undefined && (
          currentUser ? (
            <form method="post" action={`/${owner}/${repo}/star`} style="display:inline">
              <button
                type="submit"
                class={`star-btn${starred ? " starred" : ""}`}
              >
                {starred ? "\u2605" : "\u2606"} {starCount}
              </button>
            </form>
          ) : (
            <span class="star-btn">
              {"\u2606"} {starCount}
            </span>
          )
        )}
      </div>
    </div>
  );
};

export const RepoNav: FC<{
  owner: string;
  repo: string;
  active:
    | "code"
    | "commits"
    | "issues"
    | "pulls"
    | "releases"
    | "actions"
    | "gates"
    | "insights"
    | "explain"
    | "changelog"
    | "semantic"
    | "wiki"
    | "projects"
    | "agents"
    | "discussions"
    | "security"
    | "settings"
    | "debt-map"
    | "migrate"
    | "deployments"
    | "nl-search"
    | "contributors"
    | "pulse"
    | "traffic"
    | "pipeline"
    | "workspace"
    | "archaeology";
  /** Current authenticated user — used for owner-only tab gating. */
  currentUser?: string | null;
  /** Repo owner username — used for owner-only tab gating. */
  repoOwner?: string;
}> = ({ owner, repo, active, currentUser, repoOwner }) => (
  <div class="repo-nav">
    <a href={`/${owner}/${repo}`} class={active === "code" ? "active" : ""}>
      Code
    </a>
    <a
      href={`/${owner}/${repo}/issues`}
      class={active === "issues" ? "active" : ""}
    >
      Issues
    </a>
    <a
      href={`/${owner}/${repo}/discussions`}
      class={active === "discussions" ? "active" : ""}
    >
      Discussions
    </a>
    <a
      href={`/${owner}/${repo}/wiki`}
      class={active === "wiki" ? "active" : ""}
    >
      Wiki
    </a>
    <a
      href={`/${owner}/${repo}/pulls`}
      class={active === "pulls" ? "active" : ""}
    >
      Pull Requests
    </a>
    <a
      href={`/${owner}/${repo}/projects`}
      class={active === "projects" ? "active" : ""}
    >
      Projects
    </a>
    <a
      href={`/${owner}/${repo}/commits`}
      class={active === "commits" ? "active" : ""}
    >
      Commits
    </a>
    <a
      href={`/${owner}/${repo}/actions`}
      class={active === "actions" ? "active" : ""}
    >
      Actions
    </a>
    <a
      href={`/${owner}/${repo}/releases`}
      class={active === "releases" ? "active" : ""}
    >
      Releases
    </a>
    <a
      href={`/${owner}/${repo}/contributors`}
      class={active === "contributors" ? "active" : ""}
    >
      Contributors
    </a>
    <a
      href={`/${owner}/${repo}/pulse`}
      class={active === "pulse" ? "active" : ""}
    >
      Pulse
    </a>
    {currentUser && repoOwner && currentUser === repoOwner && (
      <a
        href={`/${owner}/${repo}/traffic`}
        class={active === "traffic" ? "active" : ""}
      >
        Traffic
      </a>
    )}
    <a
      href={`/${owner}/${repo}/gates`}
      class={active === "gates" ? "active" : ""}
    >
      {"\u25CF"} Gates
    </a>
    <a
      href={`/${owner}/${repo}/security/vulnerabilities`}
      class={active === "security" ? "active" : ""}
    >
      Security
    </a>
    <a
      href={`/${owner}/${repo}/settings`}
      class={active === "settings" ? "active" : ""}
    >
      Settings
    </a>
    <a
      href={`/${owner}/${repo}/cloud-deployments`}
      class={active === "deployments" ? "active" : ""}
    >
      Deployments
    </a>
    <a
      href={`/${owner}/${repo}/pipeline`}
      class={active === "pipeline" ? "active" : ""}
    >
      Pipeline
    </a>
    <a
      href={`/${owner}/${repo}/insights`}
      class={active === "insights" ? "active" : ""}
    >
      Insights
    </a>
    <a
      href={`/${owner}/${repo}/agents`}
      class={active === "agents" ? "active" : ""}
    >
      Agents
    </a>
    <a
      href={`/${owner}/${repo}/explain`}
      class={`repo-nav-ai${active === "explain" ? " active" : ""}`}
      style="margin-left: auto"
    >
      {"\u2728"} Explain
    </a>
    <a href={`/${owner}/${repo}/ask`} class="repo-nav-ai">
      {"\u2728"} Ask AI
    </a>
    <a
      href={`/${owner}/${repo}/workspace`}
      class={`repo-nav-ai${active === "workspace" ? " active" : ""}`}
      title="AI Workspace — spec-to-PR, fix issues with AI, web editor"
    >
      {"✨"} Workspace
    </a>
    <a
      href={`/${owner}/${repo}/spec`}
      class="repo-nav-ai"
      title="Spec to PR — paste a feature spec, AI opens a draft PR"
    >
      {"\u2728"} Spec
    </a>
    <a
      href={`/${owner}/${repo}/ai/tests`}
      class="repo-nav-ai"
      title="AI Tests \u2014 generate failing test stubs from a source file"
    >
      {"\u2728"} Tests
    </a>
    <a
      href={`/${owner}/${repo}/debt-map`}
      class={`repo-nav-ai${active === "debt-map" ? " active" : ""}`}
      title="AI Debt Map \u2014 visual technical debt graph with Claude analysis"
    >
      {"\u2593"} Debt Map
    </a>
    <a
      href={`/${owner}/${repo}/search/nl`}
      class={`repo-nav-ai${active === "nl-search" ? " active" : ""}`}
      title="Natural Language Search \u2014 search by intent, not keywords"
    >
      {"\u2728"} NL Search
    </a>
    <a
      href={`/${owner}/${repo}/archaeology`}
      class={`repo-nav-ai${active === "archaeology" ? " active" : ""}`}
      title="AI Archaeology \u2014 excavate why any file exists using git history, PRs, and issues"
    >
      {"\ud83c\udfdb"} Archaeology
    </a>
  </div>
);

export const BranchSwitcher: FC<{
  owner: string;
  repo: string;
  currentRef: string;
  branches: string[];
  pathType: "tree" | "blob" | "commits";
  subPath?: string;
}> = ({ owner, repo, currentRef, branches, pathType, subPath }) => {
  if (branches.length <= 1) {
    return <div class="branch-selector">{currentRef}</div>;
  }

  return (
    <div class="branch-dropdown">
      <button class="branch-selector" type="button">
        {currentRef} &#9662;
      </button>
      <div class="branch-dropdown-content">
        {branches.map((branch) => {
          let href: string;
          if (pathType === "commits") {
            href = `/${owner}/${repo}/commits/${branch}`;
          } else if (subPath) {
            href = `/${owner}/${repo}/${pathType}/${branch}/${subPath}`;
          } else {
            href = `/${owner}/${repo}/tree/${branch}`;
          }
          return (
            <a
              href={href}
              class={branch === currentRef ? "active-branch" : ""}
            >
              {branch}
            </a>
          );
        })}
      </div>
    </div>
  );
};

export const Breadcrumb: FC<{
  owner: string;
  repo: string;
  ref: string;
  path: string;
}> = ({ owner, repo, ref, path }) => {
  const parts = path.split("/").filter(Boolean);
  const crumbs: { name: string; href: string }[] = [
    { name: repo, href: `/${owner}/${repo}/tree/${ref}` },
  ];
  let accumulated = "";
  for (const part of parts) {
    accumulated += (accumulated ? "/" : "") + part;
    crumbs.push({
      name: part,
      href: `/${owner}/${repo}/tree/${ref}/${accumulated}`,
    });
  }
  return (
    <div class="breadcrumb">
      {crumbs.map((crumb, i) => (
        <>
          {i > 0 && <span>/</span>}
          {i === crumbs.length - 1 ? (
            <strong>{crumb.name}</strong>
          ) : (
            <a href={crumb.href}>{crumb.name}</a>
          )}
        </>
      ))}
    </div>
  );
};

export const FileTable: FC<{
  entries: GitTreeEntry[];
  owner: string;
  repo: string;
  ref: string;
  path: string;
}> = ({ entries, owner, repo, ref, path }) => (
  <table class="file-table">
    <tbody>
      {entries.map((entry) => {
        const fullPath = path ? `${path}/${entry.name}` : entry.name;
        const href =
          entry.type === "tree"
            ? `/${owner}/${repo}/tree/${ref}/${fullPath}`
            : `/${owner}/${repo}/blob/${ref}/${fullPath}`;
        return (
          <tr>
            <td class="file-icon">
              {entry.type === "tree" ? "\u{1F4C1}" : "\u{1F4C4}"}
            </td>
            <td class="file-name">
              <a href={href}>{entry.name}</a>
            </td>
            <td style="text-align: right; color: var(--text-muted); font-size: 13px;">
              {entry.size !== undefined ? formatSize(entry.size) : ""}
            </td>
          </tr>
        );
      })}
    </tbody>
  </table>
);

export const HighlightedCode: FC<{
  highlightedHtml: string;
  lineCount: number;
}> = ({ highlightedHtml, lineCount }) => {
  const lineNums = Array.from({ length: lineCount }, (_, i) => i + 1);
  return (
    <div class="blob-code">
      <table>
        <tbody>
          <tr>
            <td class="line-num" style="vertical-align: top; padding-top: 0; padding-bottom: 0">
              <pre style="margin: 0; line-height: 1.6; font-size: 13px">
                {lineNums.map((n) => (
                  <>
                    <span>{n}</span>
                    {"\n"}
                  </>
                ))}
              </pre>
            </td>
            <td class="line-content" style="vertical-align: top; padding-top: 0; padding-bottom: 0">
              <pre style="margin: 0; line-height: 1.6; font-size: 13px">{html([highlightedHtml] as unknown as TemplateStringsArray)}</pre>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  );
};

export const PlainCode: FC<{ lines: string[] }> = ({ lines }) => (
  <div class="blob-code">
    <table>
      <tbody>
        {lines.map((line, i) => (
          <tr>
            <td class="line-num">{i + 1}</td>
            <td class="line-content">{line}</td>
          </tr>
        ))}
      </tbody>
    </table>
  </div>
);

export const CommitList: FC<{
  commits: GitCommit[];
  owner: string;
  repo: string;
  verifications?: Record<string, { verified: boolean; reason: string }>;
}> = ({ commits, owner, repo, verifications }) => (
  <div class="commit-list">
    {commits.map((commit) => {
      const v = verifications?.[commit.sha];
      return (
        <div class="commit-item">
          <div>
            <div class="commit-message">
              <a href={`/${owner}/${repo}/commit/${commit.sha}`}>
                {commit.message}
              </a>
              {v?.verified && (
                <a
                  href="/settings/signing-keys"
                  title="Signed with a registered key — manage your signing keys"
                  style="margin-left:8px;font-size:10px;padding:1px 6px;border-radius:3px;background:var(--green,#2ea043);color:#fff;text-transform:uppercase;letter-spacing:.4px;text-decoration:none"
                >
                  Verified
                </a>
              )}
            </div>
            <div class="commit-meta">
              {commit.author} committed {formatRelativeDate(commit.date)}
            </div>
          </div>
          <a
            href={`/${owner}/${repo}/commit/${commit.sha}`}
            class="commit-sha"
          >
            {commit.sha.slice(0, 7)}
          </a>
        </div>
      );
    })}
  </div>
);

// ---- Diff viewer ----------------------------------------------------------

const _diffScript = `
function diffToggleView(id,mode){
  var v=document.getElementById(id);if(!v)return;
  v.querySelectorAll('.diff-table-inline').forEach(function(t){t.hidden=(mode==='split');});
  v.querySelectorAll('.diff-table-split').forEach(function(t){t.hidden=(mode!=='split');});
  v.querySelectorAll('.diff-view-btn').forEach(function(b){b.classList.remove('active');});
  var btn=v.querySelector('.diff-view-btn-'+mode);if(btn)btn.classList.add('active');
}
function diffToggleFile(id){
  var body=document.getElementById(id);if(!body)return;
  body.hidden=!body.hidden;
  var hdr=body.previousElementSibling;if(hdr)hdr.classList.toggle('collapsed',body.hidden);
}
`;

export const DiffView: FC<{ raw: string; files: GitDiffFile[] }> = ({
  raw,
  files,
}) => {
  const parsed = parseDiff(raw);
  const totalAdd = files.reduce((s, f) => s + f.additions, 0);
  const totalDel = files.reduce((s, f) => s + f.deletions, 0);

  if (parsed.length === 0 && files.length === 0) {
    return (
      <div class="diff-view">
        <p style="color:var(--text-muted);font-size:14px">No changes.</p>
      </div>
    );
  }

  return (
    <div class="diff-view" id="diff-view-main">
      <script dangerouslySetInnerHTML={{ __html: _diffScript }} />

      {/* Toolbar */}
      <div class="diff-toolbar">
        <div class="diff-summary">
          <strong>{files.length}</strong> file{files.length !== 1 ? "s" : ""} changed,{" "}
          <span class="stat-add">+{totalAdd}</span>{" "}
          <span class="stat-del">-{totalDel}</span>
        </div>
        <div class="diff-view-toggle">
          <button class="diff-view-btn diff-view-btn-inline active" onclick="diffToggleView('diff-view-main','inline')" type="button">Inline</button>
          <button class="diff-view-btn diff-view-btn-split" onclick="diffToggleView('diff-view-main','split')" type="button">Split</button>
        </div>
      </div>

      {/* File jump list (shown when > 1 file) */}
      {parsed.length > 1 && (
        <div class="diff-jump-list">
          {parsed.map((f, i) => {
            const isAdd = f.additions > 0 && f.deletions === 0;
            const isDel = f.additions === 0 && f.deletions > 0;
            return (
              <a class="diff-jump-item" href={`#diff-file-${i}`}>
                <span class={isAdd ? "stat-add" : isDel ? "stat-del" : "diff-jump-mod"}>
                  {isAdd ? "+" : isDel ? "−" : "~"}
                </span>{" "}
                {f.path.split("/").pop() || f.path}
              </a>
            );
          })}
        </div>
      )}

      {/* Per-file blocks */}
      {parsed.map((file, idx) => {
        const bodyId = `diff-body-${idx}`;
        const splitRows = pairLines(file.lines);
        return (
          <div class="diff-file" id={`diff-file-${idx}`}>
            <div class="diff-file-header" onclick={`diffToggleFile('${bodyId}')`}>
              <span class="diff-file-path" title={file.path}>{file.path}</span>
              <span class="diff-file-meta">
                {file.isBinary
                  ? <span style="color:var(--text-muted)">binary</span>
                  : <><span class="stat-add">+{file.additions}</span>{" "}<span class="stat-del">-{file.deletions}</span></>
                }
                <span class="diff-file-chevron">▾</span>
              </span>
            </div>
            <div id={bodyId}>
              {file.isBinary ? (
                <div class="diff-binary">Binary file changed</div>
              ) : (
                <>
                  {/* Inline table (default) */}
                  <table class="diff-table diff-table-inline">
                    <tbody>
                      {file.lines.map((line) => {
                        if (line.type === "hunk") {
                          return (
                            <tr class="diff-row diff-row-hunk">
                              <td class="diff-ln diff-ln-old"></td>
                              <td class="diff-ln diff-ln-new"></td>
                              <td class="diff-cell">{line.content}</td>
                            </tr>
                          );
                        }
                        const sigil = line.type === "add" ? "+" : line.type === "del" ? "-" : " ";
                        return (
                          <tr class={`diff-row diff-row-${line.type}${line.wsOnly ? " diff-row-ws" : ""}`}>
                            <td class="diff-ln diff-ln-old">{line.oldLine ?? ""}</td>
                            <td class="diff-ln diff-ln-new">{line.newLine ?? ""}</td>
                            <td class="diff-cell">
                              <span class="diff-sigil">{sigil}</span>
                              {line.content}
                              {line.wsOnly && <span class="diff-ws-badge" title="whitespace-only change">ws</span>}
                            </td>
                          </tr>
                        );
                      })}
                    </tbody>
                  </table>
                  {/* Split table (hidden until toggled) */}
                  <table class="diff-table diff-table-split" hidden>
                    <tbody>
                      {splitRows.map((row) => {
                        const isHunk = row.left?.type === "hunk" || row.right?.type === "hunk";
                        if (isHunk) {
                          const hunk = row.left ?? row.right;
                          return (
                            <tr class="diff-row diff-row-hunk">
                              <td class="diff-ln diff-ln-old"></td>
                              <td class="diff-cell">{hunk?.content ?? ""}</td>
                              <td class="diff-ln diff-ln-new"></td>
                              <td class="diff-cell"></td>
                            </tr>
                          );
                        }
                        const isCtx = row.left?.type === "ctx";
                        const L = row.left;
                        const R = row.right;
                        const leftCls = `diff-cell${L ? (isCtx ? " diff-cell-ctx" : " diff-cell-del") : " diff-cell-empty"}${L?.wsOnly ? " diff-cell-ws" : ""}`;
                        const rightCls = `diff-cell${R ? (isCtx ? " diff-cell-ctx" : " diff-cell-add") : " diff-cell-empty"}${R?.wsOnly ? " diff-cell-ws" : ""}`;
                        return (
                          <tr class="diff-row diff-split-row">
                            <td class="diff-ln diff-ln-old">{L?.oldLine ?? ""}</td>
                            <td class={leftCls}>
                              {L && <span class="diff-sigil">{isCtx ? " " : "-"}</span>}
                              {L?.content ?? ""}
                              {L?.wsOnly && <span class="diff-ws-badge" title="whitespace-only change">ws</span>}
                            </td>
                            <td class="diff-ln diff-ln-new">{R?.newLine ?? ""}</td>
                            <td class={rightCls}>
                              {R && <span class="diff-sigil">{isCtx ? " " : "+"}</span>}
                              {isCtx ? L?.content ?? "" : R?.content ?? ""}
                              {R?.wsOnly && !isCtx && <span class="diff-ws-badge" title="whitespace-only change">ws</span>}
                            </td>
                          </tr>
                        );
                      })}
                    </tbody>
                  </table>
                </>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
};

export const RepoCard: FC<{ repo: Repository; ownerName: string }> = ({
  repo,
  ownerName,
}) => (
  <div class="card">
    <h3>
      <a href={`/${ownerName}/${repo.name}`}>{repo.name}</a>
    </h3>
    {repo.description && <p>{repo.description}</p>}
    <div class="card-meta">
      {repo.isPrivate && <span class="badge">Private</span>}
      <span>{"\u2606"} {repo.starCount}</span>
      {repo.pushedAt && (
        <span>Updated {formatRelativeDate(repo.pushedAt.toString())}</span>
      )}
    </div>
  </div>
);

function formatSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function formatRelativeDate(dateStr: string): string {
  const date = new Date(dateStr);
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffMins = Math.floor(diffMs / 60000);
  if (diffMins < 1) return "just now";
  if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
  const diffHours = Math.floor(diffMins / 60);
  if (diffHours < 24)
    return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
  const diffDays = Math.floor(diffHours / 24);
  if (diffDays < 30) return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
  return date.toLocaleDateString("en-US", {
    month: "short",
    day: "numeric",
    year: "numeric",
  });
}

// ---------------------------------------------------------------------------
// CiFailureProfileCard — Phase 2 Human-Agent Canvas
// ---------------------------------------------------------------------------

export interface CiTraceIteration {
  iteration: number;
  modelRoute: string;
  errorDelta: string;
  tokenCost: number;
}

export interface CiFailureProfileProps {
  gateRunId: string;
  failureTarget: string;
  errorDelta: string;
  mitigationHint: string;
  traceLog: CiTraceIteration[];
}

export const CiFailureProfileCard: FC<CiFailureProfileProps> = ({
  gateRunId,
  failureTarget,
  errorDelta,
  mitigationHint,
  traceLog,
}) => (
  <div class="ci-failure-profile-card">
    <style>{`
      .ci-failure-profile-card {
        background: #1a1a2e;
        border: 1px solid #2d2d4a;
        border-radius: 8px;
        padding: 16px;
        margin: 12px 0;
        font-family: monospace;
        color: #e0e0ff;
      }
      .ci-failure-profile-card h3 {
        margin: 0 0 12px;
        color: #ff6b6b;
        font-size: 14px;
        text-transform: uppercase;
        letter-spacing: 0.5px;
      }
      .ci-failure-profile-card .field-label {
        color: #888;
        font-size: 11px;
        text-transform: uppercase;
        margin-top: 10px;
      }
      .ci-failure-profile-card .field-value {
        color: #e0e0ff;
        font-size: 13px;
        margin: 2px 0 6px;
        white-space: pre-wrap;
        word-break: break-word;
      }
      .ci-failure-profile-card .trace-row {
        display: grid;
        grid-template-columns: 40px 1fr 80px;
        gap: 8px;
        padding: 4px 0;
        border-bottom: 1px solid #2d2d4a;
        font-size: 12px;
      }
      .ci-failure-profile-card .feedback-row {
        margin-top: 14px;
        display: flex;
        gap: 8px;
      }
      .ci-failure-profile-card .btn-feedback {
        padding: 6px 12px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        font-size: 12px;
        font-weight: bold;
      }
      .ci-failure-profile-card .btn-helpful {
        background: #1a6b3c;
        color: #7fff9e;
      }
      .ci-failure-profile-card .btn-hallucination {
        background: #6b1a1a;
        color: #ff9e9e;
      }
    `}</style>
    <h3>🔍 CI Failure Profile</h3>
    <div class="field-label">Failure Target</div>
    <div class="field-value">{failureTarget}</div>
    <div class="field-label">Error Delta</div>
    <div class="field-value">{errorDelta}</div>
    <div class="field-label">Mitigation Hint</div>
    <div class="field-value">{mitigationHint}</div>
    {traceLog.length > 0 && (
      <>
        <div class="field-label" style="margin-top:12px">Model Trace</div>
        {traceLog.map((t) => (
          <div class="trace-row" key={t.iteration}>
            <span>#{t.iteration}</span>
            <span>{t.modelRoute}</span>
            <span>{t.tokenCost}¢</span>
          </div>
        ))}
      </>
    )}
    <div class="feedback-row">
      <form method="post" action="/api/flywheel-telemetry/feedback" style="display:inline">
        <input type="hidden" name="gateRunId" value={gateRunId} />
        <input type="hidden" name="verdict" value="helpful" />
        <button type="submit" class="btn-feedback btn-helpful">
          👍 Diagnostic Helpful
        </button>
      </form>
      <form method="post" action="/api/flywheel-telemetry/feedback" style="display:inline">
        <input type="hidden" name="gateRunId" value={gateRunId} />
        <input type="hidden" name="verdict" value="hallucination" />
        <button type="submit" class="btn-feedback btn-hallucination">
          👎 Hallucination Flagged
        </button>
      </form>
    </div>
  </div>
);

// ---------------------------------------------------------------------------
// Settings navigation — shared across every /settings/* page.
//
// Previously each settings page either duplicated a flat "pill row" nav
// (styled only on the two pages settings.tsx itself renders — every other
// importer got unstyled raw links, since the CSS lived inline in that one
// file) or, for most settings pages (tokens, billing, notifications, audit,
// saved replies, sponsors, OAuth apps/authorizations, incident hooks...),
// rendered no navigation at all. Landing on /settings/tokens was a dead end:
// no way to reach any other settings page except backing out to /settings.
//
// This is the single source of truth for the settings IA: a grouped
// sidebar (profile / access & security / applications / automation /
// account / activity), matching the standard every developer already
// knows from GitHub's own settings sidebar, covering every real
// /settings/* page in the app.
// ---------------------------------------------------------------------------

export type SettingsNavKey =
  | "profile"
  | "notifications"
  | "replies"
  | "billing"
  | "sponsors"
  | "keys"
  | "signing-keys"
  | "2fa"
  | "passkeys"
  | "sessions"
  | "tokens"
  | "applications"
  | "apps"
  | "authorizations"
  | "agents"
  | "deploy-targets"
  | "integrations"
  | "incident-hooks"
  | "audit";

interface SettingsNavItem {
  key: SettingsNavKey;
  href: string;
  label: string;
}

interface SettingsNavGroup {
  label: string;
  items: SettingsNavItem[];
}

const SETTINGS_NAV_GROUPS: SettingsNavGroup[] = [
  {
    label: "Account",
    items: [
      { key: "profile", href: "/settings", label: "Public profile" },
      { key: "notifications", href: "/settings/notifications", label: "Notifications" },
      { key: "replies", href: "/settings/replies", label: "Saved replies" },
      { key: "billing", href: "/settings/billing", label: "Billing" },
      { key: "sponsors", href: "/settings/sponsors", label: "Sponsorship" },
    ],
  },
  {
    label: "Access & security",
    items: [
      { key: "keys", href: "/settings/keys", label: "SSH keys" },
      { key: "signing-keys", href: "/settings/signing-keys", label: "Signing keys" },
      { key: "2fa", href: "/settings/2fa", label: "Two-factor auth" },
      { key: "passkeys", href: "/settings/passkeys", label: "Passkeys" },
      { key: "sessions", href: "/settings/sessions", label: "Sessions" },
      { key: "tokens", href: "/settings/tokens", label: "Personal access tokens" },
    ],
  },
  {
    label: "Applications",
    items: [
      { key: "applications", href: "/settings/applications", label: "Developer applications" },
      { key: "apps", href: "/settings/apps", label: "Installed apps" },
      { key: "authorizations", href: "/settings/authorizations", label: "Authorized applications" },
    ],
  },
  {
    label: "Automation",
    items: [
      { key: "agents", href: "/settings/agents", label: "Agent sessions" },
      { key: "deploy-targets", href: "/settings/deploy-targets", label: "Deploy targets" },
      { key: "integrations", href: "/settings/integrations", label: "Chat integrations" },
      { key: "incident-hooks", href: "/settings/incident-hooks", label: "Incident hooks" },
    ],
  },
  {
    label: "Activity",
    items: [{ key: "audit", href: "/settings/audit", label: "Audit log" }],
  },
];

export const SettingsNav: FC<{ active: SettingsNavKey }> = ({ active }) => (
  <nav class="stgnav" aria-label="Settings sections">
    {SETTINGS_NAV_GROUPS.map((group) => (
      <div class="stgnav-group">
        <div class="stgnav-label">{group.label}</div>
        {group.items.map((it) => (
          <a
            href={it.href}
            class={it.key === active ? "is-active" : ""}
            aria-current={it.key === active ? "page" : undefined}
          >
            {it.label}
          </a>
        ))}
      </div>
    ))}
  </nav>
);

/**
 * Shared shell CSS. Every /settings/* page includes this once (it's cheap,
 * inline, and idempotent — duplicate <style> blocks with the same rules
 * are harmless) and wraps its content in `.settings-shell` /
 * `.settings-content` alongside a `<SettingsNav active="...">`.
 */
export const settingsNavStyles = `
  .settings-shell {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: var(--space-6);
    align-items: start;
  }
  .stgnav {
    position: sticky;
    top: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }
  .stgnav-group {
    display: flex;
    flex-direction: column;
    gap: 1px;
  }
  .stgnav-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 4px 10px;
    margin-bottom: 2px;
  }
  .stgnav a {
    display: block;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text-muted);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background 120ms ease, color 120ms ease;
  }
  .stgnav a:hover {
    color: var(--text-strong);
    background: var(--bg-hover);
  }
  .stgnav a.is-active {
    color: var(--text-strong);
    background: rgba(91,110,232,0.14);
    box-shadow: inset 0 0 0 1px rgba(91,110,232,0.3);
    font-weight: 600;
  }
  .settings-content {
    min-width: 0;
  }
  @media (max-width: 860px) {
    .settings-shell {
      display: block;
    }
    .stgnav {
      position: static;
      flex-direction: row;
      flex-wrap: wrap;
      gap: var(--space-3);
      margin-bottom: var(--space-5);
      padding: 4px;
      background: var(--bg-elevated);
      border: 1px solid var(--border);
      border-radius: var(--radius);
    }
    .stgnav-group {
      flex-direction: row;
      flex-wrap: wrap;
      gap: 2px;
    }
    .stgnav-label {
      display: none;
    }
    .stgnav a {
      padding: 6px 12px;
      border-radius: 9999px;
    }
  }
`;
