/** @jsxImportSource solid-js */
/**
 * Stories for Agent Manager components:
 * FileTree, DiffPanel, FullScreenDiffView, WorktreeItem, TabBar
 */

import type { Meta, StoryObj } from "storybook-solidjs-vite"
import { StoryProviders, defaultMockData, mockSessionValue } from "./StoryProviders"
import { FileTree } from "../../diff-viewer/FileTree"
import { DiffPanel } from "../../agent-manager/DiffPanel"
import { FullScreenDiffView } from "../../diff-viewer/FullScreenDiffView"
import { WorktreeItem } from "../../agent-manager/WorktreeItem"
import { ChatView } from "../components/chat/ChatView"
import { registerVscodeToolOverrides } from "../components/chat/VscodeToolOverrides"
import { SessionContext } from "../context/session"
import { ServerContext } from "../context/server"
import { WorktreeModeProvider } from "../context/worktree-mode"
import { SidebarSearchMenu } from "../../agent-manager/SidebarSearchMenu"
import { SidebarToggleButton } from "../../agent-manager/SidebarToggleButton"
import type { SidebarSearchItem } from "../../agent-manager/sidebar-search"
import { Button } from "@kilocode/kilo-ui/button"
import { IconButton } from "@kilocode/kilo-ui/icon-button"
import { Icon } from "@kilocode/kilo-ui/icon"
import { TooltipKeybind } from "@kilocode/kilo-ui/tooltip"
import { ContextMenu } from "@kilocode/kilo-ui/context-menu"
import { createSignal, onCleanup, onMount, type JSX } from "solid-js"
import type { WorktreeFileDiff, WorktreeState, WorktreeGitStats, PRStatus } from "../types/messages"
import type { ReviewComment } from "../../diff-viewer/review-comments"
import "../../agent-manager/agent-manager.css"
import "../../agent-manager/agent-manager-review.css"

registerVscodeToolOverrides()

// ---------------------------------------------------------------------------
// Shared mock data
// ---------------------------------------------------------------------------

const mockDiffs: WorktreeFileDiff[] = [
  {
    file: "src/components/chat/ChatView.tsx",
    status: "modified",
    additions: 12,
    deletions: 4,
    before: `import { Component } from "solid-js"\n\nexport const ChatView: Component = () => {\n  return <div class="chat-view" />\n}\n`,
    after: `import { Component, createSignal } from "solid-js"\n\nexport const ChatView: Component = () => {\n  const [open, setOpen] = createSignal(false)\n  return <div class="chat-view" />\n}\n`,
  },
  {
    file: "src/components/chat/MessageList.tsx",
    status: "modified",
    additions: 3,
    deletions: 1,
    before: `export const MessageList = () => <div class="message-list" />\n`,
    after: `export const MessageList = () => (\n  <div class="message-list" role="log" aria-live="polite" />\n)\n`,
  },
  {
    file: "src/stories/chat.stories.tsx",
    status: "added",
    additions: 80,
    deletions: 0,
    before: "",
    after: `/** @jsxImportSource solid-js */\nimport type { Meta } from "storybook-solidjs-vite"\nconst meta: Meta = { title: "Chat" }\nexport default meta\n`,
  },
]

const context = Array.from({ length: 36 }, (_, i) => `  const item${i} = values[${i}]\n`).join("")
const foldedDiffs: WorktreeFileDiff[] = [
  {
    file: "src/components/chat/LongReview.ts",
    status: "modified",
    additions: 2,
    deletions: 2,
    before: `export function review(values: string[]) {\n  const title = "Draft"\n${context}  return title\n}\n`,
    after: `export function review(values: string[]) {\n  const title = "Ready"\n${context}  return title.toUpperCase()\n}\n`,
  },
]

const ROWS = 140
function edited(seed: string): WorktreeFileDiff {
  const before = Array.from({ length: ROWS }, (_, i) => `const row${i} = "${seed}-old-${i}"\n`).join("")
  const after = Array.from({ length: ROWS }, (_, i) => `const row${i} = "${seed}-new-${i}"\n`).join("")
  const patch = [
    "diff --git a/src/agent-edit.ts b/src/agent-edit.ts",
    "--- a/src/agent-edit.ts",
    "+++ b/src/agent-edit.ts",
    `@@ -1,${ROWS} +1,${ROWS} @@`,
    ...before
      .trimEnd()
      .split("\n")
      .map((line) => `-${line}`),
    ...after
      .trimEnd()
      .split("\n")
      .map((line) => `+${line}`),
    "",
  ].join("\n")

  return {
    file: "src/agent-edit.ts",
    status: "modified",
    additions: ROWS,
    deletions: ROWS,
    before,
    after,
    patch,
  }
}

const tail: WorktreeFileDiff = {
  file: "src/target.ts",
  status: "modified",
  additions: 1,
  deletions: 1,
  before: "const target = 'before'\n",
  after: "const target = 'after'\n",
  patch:
    "diff --git a/src/target.ts b/src/target.ts\n--- a/src/target.ts\n+++ b/src/target.ts\n@@ -1 +1 @@\n-const target = 'before'\n+const target = 'after'\n",
}

// ---------------------------------------------------------------------------
// Meta
// ---------------------------------------------------------------------------

const meta: Meta = {
  title: "AgentManager",
  parameters: { layout: "padded" },
}
export default meta
type Story = StoryObj

// ---------------------------------------------------------------------------
// Wide chat layout
// ---------------------------------------------------------------------------

const chatSessionID = "story-agent-manager-chat"
const chatUserID = "story-agent-manager-user"
const chatAssistantID = "story-agent-manager-assistant"
const chatTime = 1_718_000_000_000
const chatDiff = {
  file: "webview-ui/src/styles/chat-layout.css",
  status: "modified" as const,
  additions: 12,
  deletions: 4,
  before: ".chat-view {\n  display: flex;\n}\n",
  after: ".chat-view {\n  display: flex;\n  container: chat / inline-size;\n}\n",
}
const chatMessages = [
  {
    id: chatUserID,
    sessionID: chatSessionID,
    role: "user",
    createdAt: new Date(chatTime).toISOString(),
    time: { created: chatTime },
    summary: { diffs: [chatDiff] },
  },
  {
    id: chatAssistantID,
    sessionID: chatSessionID,
    role: "assistant",
    parentID: chatUserID,
    createdAt: new Date(chatTime + 1000).toISOString(),
    time: { created: chatTime + 1000, completed: chatTime + 5000 },
    modelID: "anthropic/claude-sonnet-4-6",
    providerID: "kilo",
    mode: "default",
    agent: "code",
    path: { cwd: "/project", root: "/project" },
  },
]
const chatParts = {
  [chatUserID]: [
    {
      id: "story-agent-manager-user-text",
      sessionID: chatSessionID,
      messageID: chatUserID,
      type: "text",
      text: "Make the full-screen Agent Manager conversation easier to scan without squeezing tool output or diffs.",
    },
  ],
  [chatAssistantID]: [
    {
      id: "story-agent-manager-assistant-text",
      sessionID: chatSessionID,
      messageID: chatAssistantID,
      type: "text",
      text: "The transcript now follows a centered 78 character reading lane. Long explanations share one consistent left edge, so the eye can move between turns without crossing the entire editor.\n\nTool output and the composer use the same lane, keeping every conversation element aligned.",
    },
    {
      id: "story-agent-manager-bash",
      sessionID: chatSessionID,
      messageID: chatAssistantID,
      type: "tool",
      callID: "story-agent-manager-bash-call",
      tool: "bash",
      state: {
        status: "completed",
        input: { command: "bun run test:unit", description: "Run focused Agent Manager tests" },
        output: "18 tests passed\n0 tests failed",
        title: "Run focused Agent Manager tests",
        metadata: {},
        time: { start: chatTime + 2000, end: chatTime + 4000 },
      },
    },
  ],
}
const chatData = {
  ...defaultMockData,
  message: { [chatSessionID]: chatMessages },
  part: chatParts,
}
const chatServer = {
  connectionState: () => "connected" as const,
  serverInfo: () => undefined,
  extensionVersion: () => "1.0.0",
  errorMessage: () => undefined,
  errorDetails: () => undefined,
  isConnected: () => true,
  profileData: () => null,
  deviceAuth: () => ({ status: "idle" as const }),
  startLogin: () => undefined,
  goToLogin: () => undefined,
  vscodeLanguage: () => "en",
  languageOverride: () => undefined,
  workspaceDirectory: () => "/project",
  gitInstalled: () => true,
}

function renderChat() {
  const session = {
    ...mockSessionValue({ id: chatSessionID, status: "idle", closeReason: "completed" }),
    messages: () => chatMessages,
    visibleMessages: () => chatMessages,
    userMessages: () => chatMessages.filter((message) => message.role === "user"),
    getParts: (id: string) => chatParts[id as keyof typeof chatParts] ?? [],
    worktreeStats: () => ({ files: 3, additions: 32, deletions: 8 }),
  }
  return (
    <StoryProviders data={chatData} sessionID={chatSessionID} status="idle" noPadding>
      <ServerContext.Provider value={chatServer}>
        <SessionContext.Provider value={session as any}>
          <WorktreeModeProvider>
            <div class="am-chat-wrapper" style={{ height: "100vh" }}>
              <ChatView onForkSession={() => undefined} />
            </div>
          </WorktreeModeProvider>
        </SessionContext.Provider>
      </ServerContext.Provider>
    </StoryProviders>
  )
}

export const ReadableChat1280: Story = {
  name: "Chat - readable wide editor",
  parameters: { layout: "fullscreen" },
  render: renderChat,
}

export const ReadableChat420: Story = {
  name: "Chat - constrained editor",
  parameters: { layout: "fullscreen" },
  render: renderChat,
}

// ---------------------------------------------------------------------------
// FileTree
// ---------------------------------------------------------------------------

export const FileTreeWithChanges: Story = {
  name: "FileTree — with modifications and additions",
  render: () => (
    <StoryProviders>
      <div style={{ width: "420px", height: "400px", overflow: "auto" }}>
        <FileTree diffs={mockDiffs} activeFile="src/components/chat/ChatView.tsx" onFileSelect={() => {}} showSummary />
      </div>
    </StoryProviders>
  ),
}

export const FileTreeEmpty: Story = {
  name: "FileTree — no changes",
  render: () => (
    <StoryProviders>
      <div style={{ width: "420px", height: "400px" }}>
        <FileTree diffs={[]} activeFile={null} onFileSelect={() => {}} />
      </div>
    </StoryProviders>
  ),
}

// ---------------------------------------------------------------------------
// DiffPanel
// ---------------------------------------------------------------------------

export const DiffPanelWithDiffs: Story = {
  name: "DiffPanel — with diffs (unified)",
  render: () => (
    <StoryProviders>
      <div style={{ width: "420px", height: "500px", display: "flex", "flex-direction": "column" }}>
        <DiffPanel
          diffs={mockDiffs}
          loading={false}
          diffStyle="unified"
          onDiffStyleChange={() => {}}
          comments={[]}
          onCommentsChange={() => {}}
          onClose={() => {}}
          onExpand={() => {}}
        />
      </div>
    </StoryProviders>
  ),
}

const buttonFixtureStyle: JSX.CSSProperties = {
  display: "inline-flex",
  "align-items": "center",
  gap: "10px",
  padding: "8px",
  background: "var(--surface-base)",
  border: "1px solid var(--border-weak-base)",
  "border-radius": "6px",
}

const buttonFixtureLabelStyle: JSX.CSSProperties = {
  color: "var(--text-weak)",
  "font-size": "var(--font-size-small)",
}

export const InlineDiffBulkActionExpandAllButton: Story = {
  name: "Inline Diff — expand all button",
  render: () => (
    <StoryProviders noPadding>
      <div style={buttonFixtureStyle}>
        <span style={buttonFixtureLabelStyle}>Inline diff action</span>
        <IconButton icon="files-expand" size="small" variant="ghost" label="Expand All" />
      </div>
    </StoryProviders>
  ),
}

export const InlineDiffBulkActionCollapseAllButton: Story = {
  name: "Inline Diff — collapse all button",
  render: () => (
    <StoryProviders noPadding>
      <div style={buttonFixtureStyle}>
        <span style={buttonFixtureLabelStyle}>Inline diff action</span>
        <IconButton icon="files-collapse" size="small" variant="ghost" label="Collapse All" />
      </div>
    </StoryProviders>
  ),
}

export const FullScreenDiffBulkActionExpandAllButton: Story = {
  name: "Full-screen Diff — expand all button",
  render: () => (
    <StoryProviders noPadding>
      <div style={buttonFixtureStyle}>
        <span style={buttonFixtureLabelStyle}>Full-screen diff action</span>
        <Button size="small" variant="ghost">
          <Icon name="chevron-grabber-vertical" size="small" />
          Expand All
        </Button>
      </div>
    </StoryProviders>
  ),
}

export const FullScreenDiffBulkActionCollapseAllButton: Story = {
  name: "Full-screen Diff — collapse all button",
  render: () => (
    <StoryProviders noPadding>
      <div style={buttonFixtureStyle}>
        <span style={buttonFixtureLabelStyle}>Full-screen diff action</span>
        <Button size="small" variant="ghost">
          <Icon name="chevron-grabber-vertical" size="small" />
          Collapse All
        </Button>
      </div>
    </StoryProviders>
  ),
}

// ---------------------------------------------------------------------------
// FullScreenDiffView
// ---------------------------------------------------------------------------

export const FullScreenDiffWithChanges: Story = {
  name: "FullScreenDiffView — with changes",
  render: () => (
    <StoryProviders>
      <div style={{ width: "420px", height: "700px", display: "flex" }}>
        <FullScreenDiffView
          diffs={mockDiffs}
          loading={false}
          diffStyle="unified"
          onDiffStyleChange={() => {}}
          comments={[]}
          onCommentsChange={() => {}}
          onClose={() => {}}
        />
      </div>
    </StoryProviders>
  ),
}

export const FullScreenDiffWithCollapsedContext: Story = {
  name: "FullScreenDiffView - collapsed unchanged context",
  render: () => (
    <StoryProviders>
      <div style={{ width: "420px", height: "700px", display: "flex" }}>
        <FullScreenDiffView
          diffs={foldedDiffs}
          loading={false}
          diffStyle="unified"
          onDiffStyleChange={() => {}}
          comments={[]}
          onCommentsChange={() => {}}
          onClose={() => {}}
        />
      </div>
    </StoryProviders>
  ),
}

export const FullScreenDiffAgentEditScroll: Story = {
  name: "FullScreenDiffView - preserve scroll during agent edit",
  render: () => {
    const [diffs, setDiffs] = createSignal([edited("before"), tail])
    const [version, setVersion] = createSignal("before")
    const [key, setKey] = createSignal("agent-edit-scroll")
    const [comments, setComments] = createSignal<ReviewComment[]>([])
    const update = () => {
      setDiffs([edited("after"), tail])
      setVersion("after")
    }
    const change = () => {
      setDiffs([edited("context"), tail])
      setKey("changed-context")
    }
    return (
      <StoryProviders noPadding>
        <div style={{ height: "700px", display: "flex", "flex-direction": "column" }}>
          <div style={{ display: "flex", gap: "8px", padding: "4px", "align-items": "center" }}>
            <Button size="small" onClick={update}>
              Apply agent edit
            </Button>
            <Button size="small" onClick={change}>
              Switch review context
            </Button>
            <span data-testid="agent-edit-version">{version()}</span>
            <span data-testid="review-context">{key()}</span>
          </div>
          <div style={{ display: "flex", "min-height": "0", flex: "1" }}>
            <FullScreenDiffView
              diffs={diffs()}
              loading={false}
              sessionKey={key()}
              diffStyle="unified"
              onDiffStyleChange={() => {}}
              comments={comments()}
              onCommentsChange={setComments}
              onClose={() => {}}
            />
          </div>
        </div>
      </StoryProviders>
    )
  },
}

// ---------------------------------------------------------------------------
// WorktreeItem — shared mock helpers
// ---------------------------------------------------------------------------

const noop = () => {}

const baseWorktree: WorktreeState = {
  id: "wt-abc123",
  branch: "feat/inline-delete",
  path: "/tmp/worktrees/feat-inline-delete",
  parentBranch: "main",
  remote: "origin",
  createdAt: new Date(Date.now() - 3600_000).toISOString(),
}

const baseStats: WorktreeGitStats = {
  worktreeId: "wt-abc123",
  files: 4,
  additions: 32,
  deletions: 8,
  ahead: 2,
  behind: 0,
}

const defaultProps = {
  worktree: baseWorktree,
  label: "feat/inline-delete",
  active: false,
  pendingDelete: false,
  busy: false,
  working: false,
  stale: false,
  shortcut: 2,
  sessions: 1,
  grouped: false,
  groupStart: false,
  groupEnd: false,
  groupSize: 0,
  renaming: false,
  renameValue: "",
  closeKeybind: "⌘⇧W",
  openKeybind: "⌘⇧O",
  onClick: noop,
  onDelete: noop,
  onStartRename: noop,
  onRenameInput: noop,
  onCommitRename: noop,
  onCancelRename: noop,
  onRemoveStale: noop,
  onCopyPath: noop,
  onOpen: noop,
}

// ---------------------------------------------------------------------------
// WorktreeItem stories
// ---------------------------------------------------------------------------

export const WorktreeItemDefault: Story = {
  name: "WorktreeItem — default",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} />
      </div>
    </StoryProviders>
  ),
}

export const WorktreeItemActive: Story = {
  name: "WorktreeItem — active",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} active />
      </div>
    </StoryProviders>
  ),
}

export const WorktreeItemPendingDelete: Story = {
  name: "WorktreeItem — pending delete",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} active pendingDelete />
      </div>
    </StoryProviders>
  ),
}

export const WorktreeItemBusy: Story = {
  name: "WorktreeItem — busy (spinner)",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} busy />
      </div>
    </StoryProviders>
  ),
}

export const WorktreeItemStale: Story = {
  name: "WorktreeItem — stale",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stale />
      </div>
    </StoryProviders>
  ),
}

export const WorktreeItemWithStats: Story = {
  name: "WorktreeItem — with git stats",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} />
      </div>
    </StoryProviders>
  ),
}

// ---------------------------------------------------------------------------
// PR badge mock helpers
// ---------------------------------------------------------------------------

const basePR: PRStatus = {
  number: 8594,
  title: "feat: add inline delete",
  url: "https://github.com/org/repo/pull/8594",
  state: "open",
  review: null,
  checks: { status: "success", total: 5, passed: 5, failed: 0, pending: 0, items: [] },
  additions: 978,
  deletions: 202,
  files: 12,
}

// ---------------------------------------------------------------------------
// WorktreeItem — PR badge stories
// ---------------------------------------------------------------------------

export const PRBadgeApproved: Story = {
  name: "PR Badge — approved + checks pass",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, review: "approved" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgePending: Story = {
  name: "PR Badge — pending review",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, review: "pending" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeChangesRequested: Story = {
  name: "PR Badge — changes requested",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, review: "changes_requested" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeChecksFailing: Story = {
  name: "PR Badge — checks failing",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem
          {...defaultProps}
          stats={baseStats}
          pr={{ ...basePR, checks: { ...basePR.checks, status: "failure", passed: 3, failed: 2 } }}
        />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeChecksPending: Story = {
  name: "PR Badge — checks pending",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem
          {...defaultProps}
          stats={baseStats}
          pr={{ ...basePR, checks: { ...basePR.checks, status: "pending", passed: 2, pending: 3 } }}
        />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeDraft: Story = {
  name: "PR Badge — draft",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, state: "draft" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeMerged: Story = {
  name: "PR Badge — merged",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, state: "merged" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeClosed: Story = {
  name: "PR Badge — closed",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={{ ...basePR, state: "closed" }} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeNoReview: Story = {
  name: "PR Badge — open, no review decision",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem {...defaultProps} stats={baseStats} pr={basePR} />
      </div>
    </StoryProviders>
  ),
}

export const PRBadgeApprovedChecksFailing: Story = {
  name: "PR Badge — approved but checks failing",
  render: () => (
    <StoryProviders noPadding>
      <div style={{ width: "200px" }}>
        <WorktreeItem
          {...defaultProps}
          stats={baseStats}
          pr={{ ...basePR, review: "approved", checks: { ...basePR.checks, status: "failure", passed: 3, failed: 2 } }}
        />
      </div>
    </StoryProviders>
  ),
}

// ---------------------------------------------------------------------------
// WorktreeItem — grouped
// ---------------------------------------------------------------------------

export const WorktreeItemGrouped: Story = {
  name: "WorktreeItem — grouped (3 versions)",
  render: () => {
    const group: WorktreeState[] = [
      { ...baseWorktree, id: "wt-g1", branch: "feat/v1", groupId: "g1" },
      { ...baseWorktree, id: "wt-g2", branch: "feat/v2", groupId: "g1" },
      { ...baseWorktree, id: "wt-g3", branch: "feat/v3", groupId: "g1" },
    ]
    return (
      <StoryProviders noPadding>
        <div style={{ width: "200px" }}>
          <WorktreeItem
            {...defaultProps}
            worktree={group[0]}
            label="feat/v1"
            grouped
            groupStart
            groupEnd={false}
            groupSize={3}
            shortcut={2}
          />
          <WorktreeItem
            {...defaultProps}
            worktree={group[1]}
            label="feat/v2"
            grouped
            groupStart={false}
            groupEnd={false}
            groupSize={0}
            shortcut={3}
          />
          <WorktreeItem
            {...defaultProps}
            worktree={group[2]}
            label="feat/v3"
            grouped
            groupStart={false}
            groupEnd
            groupSize={0}
            shortcut={4}
          />
        </div>
      </StoryProviders>
    )
  },
}

// ---------------------------------------------------------------------------
// TabBar — renders tab bar structure matching SortableTab / SortableReviewTab
// DOM to verify the tooltip-trigger height chain is correct.
// ---------------------------------------------------------------------------

/**
 * Mock tab matching the real SortableTab DOM:
 *   .am-tab-sortable > [context-menu-trigger] > [tooltip-trigger] > .am-tab
 */
const MockTab = (props: { title: string; active?: boolean }) => (
  <div class="am-tab-sortable">
    <ContextMenu>
      <ContextMenu.Trigger as="div" style={{ display: "contents" }}>
        <TooltipKeybind title={props.title} keybind="⌘1" placement="bottom" inactive={props.active}>
          <div class={`am-tab ${props.active ? "am-tab-active" : ""}`}>
            <span class="am-tab-label">{props.title}</span>
            <TooltipKeybind title="Close" keybind="⌘W" placement="bottom" class="am-tab-close-wrap">
              <IconButton icon="close-small" size="small" variant="ghost" label="Close" class="am-tab-close" />
            </TooltipKeybind>
          </div>
        </TooltipKeybind>
      </ContextMenu.Trigger>
    </ContextMenu>
  </div>
)

/** Mock review tab matching SortableReviewTab DOM (no ContextMenu wrapper). */
const MockReviewTab = (props: { active?: boolean }) => (
  <div class="am-tab-sortable">
    <TooltipKeybind title="Toggle review" keybind="⌘⇧R" placement="bottom" inactive={props.active}>
      <div class={`am-tab am-tab-review ${props.active ? "am-tab-active" : ""}`}>
        <span class="am-tab-icon">
          <Icon name="layers" size="small" />
        </span>
        <span class="am-tab-label">Review</span>
        <TooltipKeybind title="Close" keybind="⌘W" placement="bottom" class="am-tab-close-wrap">
          <IconButton icon="close-small" size="small" variant="ghost" label="Close" class="am-tab-close" />
        </TooltipKeybind>
      </div>
    </TooltipKeybind>
  </div>
)

const MockTabLeading = () => (
  <div class="am-tab-leading">
    <SidebarToggleButton collapsed={false} onClick={() => {}} />
  </div>
)

const MockTabAdd = () => (
  <div class="am-tab-add-wrap">
    <div class="am-tab-add-separator" />
    <div class="am-split-button am-tab-add-split">
      <TooltipKeybind title="New session" keybind="⌘T" placement="bottom">
        <IconButton icon="plus" size="small" variant="ghost" label="New session" class="am-tab-add" />
      </TooltipKeybind>
    </div>
  </div>
)

export const TabBarMultipleTabs: Story = {
  name: "TabBar — multiple tabs with active",
  render: () => (
    <StoryProviders noPadding>
      <div class="am-tab-bar">
        <MockTabLeading />
        <div class="am-tab-scroll-area">
          <div class="am-tab-list-wrap">
            <div class="am-tab-list" style={{ "--tab-count": "3" } as JSX.CSSProperties}>
              <MockTab title="Implement auth" active />
              <MockTab title="Fix button styles" />
              <MockTab title="Add unit tests" />
            </div>
          </div>
        </div>
        <MockTabAdd />
        <div class="am-tab-actions">
          <button class="am-diff-toggle-btn am-diff-toggle-has-changes">
            <Icon name="layers" size="small" />
            <span class="am-diff-toggle-stats">
              <span class="am-stat-files">4f</span>
              <span class="am-stat-additions">+32</span>
              <span class="am-stat-deletions">−8</span>
            </span>
          </button>
          <IconButton icon="console" size="small" variant="ghost" label="Terminal" />
        </div>
      </div>
    </StoryProviders>
  ),
}

export const TabBarWithReviewTab: Story = {
  name: "TabBar — with review tab",
  render: () => (
    <StoryProviders noPadding>
      <div class="am-tab-bar">
        <MockTabLeading />
        <div class="am-tab-scroll-area">
          <div class="am-tab-list-wrap">
            <div class="am-tab-list" style={{ "--tab-count": "2" } as JSX.CSSProperties}>
              <MockTab title="Implement auth" />
              <MockReviewTab active />
            </div>
          </div>
        </div>
        <MockTabAdd />
        <div class="am-tab-actions">
          <IconButton icon="expand" size="small" variant="ghost" label="Review" class="am-tab-diff-btn-active" />
          <IconButton icon="console" size="small" variant="ghost" label="Terminal" />
        </div>
      </div>
    </StoryProviders>
  ),
}

export const TabBarSingleTab: Story = {
  name: "TabBar — single active tab",
  render: () => (
    <StoryProviders noPadding>
      <div class="am-tab-bar">
        <MockTabLeading />
        <div class="am-tab-scroll-area">
          <div class="am-tab-list-wrap">
            <div class="am-tab-list" style={{ "--tab-count": "1" } as JSX.CSSProperties}>
              <MockTab title="PR #6966 worktree checkout" active />
            </div>
          </div>
        </div>
        <MockTabAdd />
        <div class="am-tab-actions">
          <button class="am-diff-toggle-btn am-diff-toggle-has-changes">
            <Icon name="layers" size="small" />
            <span class="am-diff-toggle-stats">
              <span class="am-stat-files">188f</span>
              <span class="am-stat-additions">+23625</span>
              <span class="am-stat-deletions">−359</span>
            </span>
          </button>
          <IconButton icon="console" size="small" variant="ghost" label="Terminal" />
        </div>
      </div>
    </StoryProviders>
  ),
}

const searchSection = { id: "polish", name: "Polish", color: "Blue", order: 0, collapsed: false }
const slackedSection = { id: "slacked", name: "SLACKED", color: "Yellow", order: 1, collapsed: false }
const sidebarSearchItems: SidebarSearchItem[] = [
  {
    key: "session:session-build",
    kind: "session",
    group: "sessions",
    title: "Build grouped worktree search",
    meta: ["Polish", "Agent Manager search", "feat/sidebar-search"],
    search: "Build grouped worktree search Agent Manager search feat/sidebar-search Polish",
    sessionId: "session-build",
    location: "worktree",
    worktreeId: "wt-search",
    updatedAt: new Date(Date.now() - 3 * 60_000).toISOString(),
    state: "busy",
    visible: true,
    section: searchSection,
  },
  {
    key: "session:session-local",
    kind: "session",
    group: "sessions",
    title: "Investigate local indexing",
    meta: ["local"],
    search: "Investigate local indexing local",
    sessionId: "session-local",
    location: "local",
    updatedAt: new Date(Date.now() - 8 * 60_000).toISOString(),
    state: "idle",
    visible: true,
  },
  {
    key: "session:session-render",
    kind: "session",
    group: "sessions",
    title: "Render images in diff viewer",
    meta: ["SLACKED", "images diff viewer", "utopian-approval"],
    search: "Render images in diff viewer SLACKED images diff viewer utopian-approval",
    sessionId: "session-render",
    location: "worktree",
    worktreeId: "wt-render",
    updatedAt: new Date(Date.now() - 60 * 60_000).toISOString(),
    state: "idle",
    visible: true,
    section: slackedSection,
  },
  {
    key: "local",
    kind: "local",
    group: "contexts",
    title: "local",
    meta: ["main"],
    search: "local main",
    updatedAt: new Date(Date.now() - 3 * 60_000).toISOString(),
    state: "idle",
    visible: true,
    count: 2,
  },
  {
    key: "worktree:wt-search",
    kind: "worktree",
    group: "contexts",
    title: "Agent Manager search",
    meta: ["Polish", "feat/sidebar-search"],
    search: "Agent Manager search Polish feat/sidebar-search",
    worktreeId: "wt-search",
    updatedAt: new Date(Date.now() - 3 * 60_000).toISOString(),
    state: "busy",
    visible: true,
    section: searchSection,
    count: 2,
  },
]

export const SidebarSearchOpen: Story = {
  name: "Sidebar search — worktrees and sessions",
  render: () => {
    const [selected, setSelected] = createSignal("worktree:wt-search")
    let prompt!: HTMLTextAreaElement
    const refocus = () => requestAnimationFrame(() => prompt.focus())
    onMount(() => {
      window.addEventListener("focusPrompt", refocus)
      onCleanup(() => window.removeEventListener("focusPrompt", refocus))
    })
    return (
      <StoryProviders noPadding>
        <div style={{ "min-height": "430px", padding: "16px", background: "var(--surface-base)" }}>
          <div class="am-section-header">
            <span class="am-section-label">WORKTREES</span>
            <div class="am-section-actions">
              <SidebarSearchMenu
                items={() => sidebarSearchItems}
                keybind="⌘F"
                current={() => sidebarSearchItems.find((item) => item.key === selected())}
                labels={{
                  search: "Search worktrees and sessions",
                  scope: "Searches the local workspace, local sessions, worktrees, and their sessions",
                  contexts: "LOCAL & WORKTREES",
                  sessions: "SESSIONS",
                  waiting: "Wait",
                  retry: "Retry",
                }}
                onSelect={(item) => setSelected(item.key)}
                defaultOpen
                portal={false}
              />
            </div>
          </div>
          <output class="sr-only" data-slot="sidebar-search-selection">
            {selected()}
          </output>
          <textarea ref={prompt} class="sr-only" aria-label="Story prompt" />
        </div>
      </StoryProviders>
    )
  },
}
