// Permission option kinds (from ACP protocol)
export type PermissionOptionKind =
  | 'allow_once'
  | 'allow_always'
  | 'reject_once'
  | 'reject_always'

// Permission option (from ACP protocol)
export interface PermissionOption {
  optionId: string
  name: string
  kind: PermissionOptionKind
}

// Permission request payload (sent from server to client)
export interface PermissionRequestPayload {
  requestId: string // Unique ID for this request (generated by server)
  sessionId: string
  options: PermissionOption[]
  toolCall: {
    toolCallId: string // Tool call ID to match with existing tool calls
    title?: string
    content?: ToolCallContent[]
  }
}

// Permission response (sent from client to server)
export interface PermissionResponsePayload {
  requestId: string
  outcome: { outcome: 'cancelled' } | { outcome: 'selected'; optionId: string }
}

// ============================================================================
// Browser Tool Types
// ============================================================================
// IMPORTANT: These types MUST stay in sync with packages/proxy-server/src/mcp/types.ts
// They define the protocol between proxy-server and browser extension.
// ============================================================================

export interface BrowserToolParams {
  action: 'tabs' | 'read' | 'execute'
  tabId?: number // Required for read/execute
  script?: string // Required for execute
}

export interface BrowserTabInfo {
  id: number
  url: string
  title: string
  active: boolean
}

export interface BrowserTabsResult {
  action: 'tabs'
  tabs: BrowserTabInfo[]
}

export interface BrowserReadResult {
  action: 'read'
  tabId: number
  url: string
  title: string
  dom: string
  viewport: {
    width: number
    height: number
    scrollX: number
    scrollY: number
  }
  selection: string | null
}

export interface BrowserExecuteResult {
  action: 'execute'
  tabId: number
  url: string
  result?: unknown
  error?: string
}

export type BrowserToolResult =
  | BrowserTabsResult
  | BrowserReadResult
  | BrowserExecuteResult

// Messages sent TO the proxy server
// Reference: Zed's MessageEditor.contents() builds Vec<acp::ContentBlock>
export type ProxyMessage =
  | { type: 'connect' }
  | { type: 'disconnect' }
  | { type: 'new_session'; payload?: { cwd?: string; permissionMode?: string } }
  | { type: 'prompt'; payload: { content: ContentBlock[] } } // Changed from { text: string } to match Zed
  | { type: 'cancel' }
  | { type: 'permission_response'; payload: PermissionResponsePayload }
  | {
      type: 'browser_tool_result'
      callId: string
      result: BrowserToolResult | { error: string }
    }
  | { type: 'set_session_model'; payload: { modelId: string } }
  // Session history operations - Reference: Zed's AgentSessionList trait
  | { type: 'list_sessions'; payload?: ListSessionsRequest }
  | { type: 'load_session'; payload: LoadSessionRequest }
  | { type: 'resume_session'; payload: ResumeSessionRequest }
  // Heartbeat
  | { type: 'ping' }

// Messages received FROM the proxy server
// Reference: Zed's AgentConnection stores agentCapabilities from initialize response
export interface ProxyStatusMessage {
  type: 'status'
  payload: {
    connected: boolean
    agentInfo?: { name?: string; version?: string }
    /** Full agent capabilities from initialize response */
    capabilities?: AgentCapabilities
  }
}

export interface ProxyErrorMessage {
  type: 'error'
  payload: { message: string }
}

// Reference: Zed's session/initialize response includes promptCapabilities and models
export interface ProxySessionCreatedMessage {
  type: 'session_created'
  payload: {
    sessionId: string
    promptCapabilities?: PromptCapabilities // From agent's initialize response
    models?: SessionModelState | null // Model state if agent supports model selection
  }
}

export interface ProxySessionUpdateMessage {
  type: 'session_update'
  payload: {
    sessionId: string
    update: SessionUpdate
  }
}

export interface ProxyPromptCompleteMessage {
  type: 'prompt_complete'
  payload: { stopReason: string }
}

export interface ProxyPermissionRequestMessage {
  type: 'permission_request'
  payload: PermissionRequestPayload
}

export interface ProxyBrowserToolCallMessage {
  type: 'browser_tool_call'
  callId: string
  params: BrowserToolParams
}

export interface ProxyPongMessage {
  type: 'pong'
}

export interface ProxyModelChangedMessage {
  type: 'model_changed'
  payload: {
    modelId: string
  }
}

// ============================================================================
// Session History Response Types
// Reference: Zed's AgentSessionList in acp_thread/src/connection.rs
// ============================================================================

/**
 * Response containing list of sessions.
 * Reference: Zed's AgentSessionListResponse
 */
export interface ProxySessionListMessage {
  type: 'session_list'
  payload: ListSessionsResponse
}

/**
 * Response when a session is loaded (with history replay).
 * Reference: Zed's load_session returns Entity<AcpThread>
 */
export interface ProxySessionLoadedMessage {
  type: 'session_loaded'
  payload: {
    sessionId: string
    promptCapabilities?: PromptCapabilities
    models?: SessionModelState | null
  }
}

/**
 * Response when a session is resumed (without history replay).
 * Reference: Zed's resume_session returns Entity<AcpThread>
 */
export interface ProxySessionResumedMessage {
  type: 'session_resumed'
  payload: {
    sessionId: string
    promptCapabilities?: PromptCapabilities
    models?: SessionModelState | null
  }
}

export type ProxyResponse =
  | ProxyStatusMessage
  | ProxyErrorMessage
  | ProxySessionCreatedMessage
  | ProxySessionUpdateMessage
  | ProxyPromptCompleteMessage
  | ProxyPermissionRequestMessage
  | ProxyBrowserToolCallMessage
  | ProxyModelChangedMessage
  | ProxyPongMessage
  // Session history responses
  | ProxySessionListMessage
  | ProxySessionLoadedMessage
  | ProxySessionResumedMessage

// Content block types (matches @agentclientprotocol/sdk ContentBlock)
// Reference: Zed's acp::ContentBlock in agent-client-protocol crate
export interface TextContent {
  type: 'text'
  text: string
}

export interface ImageContent {
  type: 'image'
  mimeType: string
  data: string // base64 encoded image data
  uri?: string // optional URI for the image source
}

export interface ResourceLinkContent {
  type: 'resource_link'
  uri: string
  name: string
  title?: string
  description?: string
  mimeType?: string
  size?: number
}

export type ContentBlock =
  | TextContent
  | ImageContent
  | ResourceLinkContent
  | { type: string; text?: string }

// Session update types from ACP
export interface AgentMessageChunkUpdate {
  sessionUpdate: 'agent_message_chunk'
  content: ContentBlock
}

// Tool call content types from ACP
export interface ToolCallContentBlock {
  type: 'content'
  content: ContentBlock
}

export interface ToolCallDiffContent {
  type: 'diff'
  path: string
  oldText?: string | null
  newText: string
}

export interface ToolCallTerminalContent {
  type: 'terminal'
  terminalId: string
}

export type ToolCallContent =
  | ToolCallContentBlock
  | ToolCallDiffContent
  | ToolCallTerminalContent

export interface ToolCallUpdate {
  sessionUpdate: 'tool_call'
  toolCallId: string
  title: string
  status: string
  content?: ToolCallContent[]
  rawInput?: Record<string, unknown>
  rawOutput?: Record<string, unknown>
}

export interface ToolCallStatusUpdate {
  sessionUpdate: 'tool_call_update'
  toolCallId: string
  status?: string
  title?: string
  content?: ToolCallContent[]
  rawInput?: Record<string, unknown>
  rawOutput?: Record<string, unknown>
}

export interface AgentThoughtChunkUpdate {
  sessionUpdate: 'agent_thought_chunk'
  content: ContentBlock
}

export type PlanEntryPriority = 'high' | 'medium' | 'low'
export type PlanEntryStatus = 'pending' | 'in_progress' | 'completed'

export interface PlanEntry {
  _meta?: Record<string, unknown> | null
  content: string
  priority: PlanEntryPriority
  status: PlanEntryStatus
}

export interface PlanUpdate {
  sessionUpdate: 'plan'
  _meta?: Record<string, unknown> | null
  entries: PlanEntry[]
}

export interface UserMessageChunkUpdate {
  sessionUpdate: 'user_message_chunk'
  content: ContentBlock
}

// Available command from agent (matches ACP SDK AvailableCommand)
export interface AvailableCommand {
  name: string
  description: string
  input?: { hint: string }
}

export interface AvailableCommandsUpdate {
  sessionUpdate: 'available_commands_update'
  availableCommands: AvailableCommand[]
}

export type SessionUpdate =
  | AgentMessageChunkUpdate
  | ToolCallUpdate
  | ToolCallStatusUpdate
  | AgentThoughtChunkUpdate
  | PlanUpdate
  | UserMessageChunkUpdate
  | AvailableCommandsUpdate

// Connection state
export type ConnectionState =
  | 'disconnected'
  | 'connecting'
  | 'connected'
  | 'error'

// PromptCapabilities from ACP protocol
// Reference: Zed's acp::PromptCapabilities in agent-client-protocol crate
// Used to check what content types the agent supports
export interface PromptCapabilities {
  audio?: boolean // Agent supports audio content
  embeddedContext?: boolean // Agent supports embedded context in prompts
  image?: boolean // Agent supports image content
}

// ============================================================================
// Session Capabilities Types (matches @agentclientprotocol/sdk exactly)
// Reference: Zed's AgentCapabilities in agent_servers/src/acp.rs
// SDK types: @agentclientprotocol/sdk/dist/schema/types.gen.d.ts
// ============================================================================

/**
 * MCP capabilities supported by the agent.
 * Reference: acp::McpCapabilities
 */
export interface McpCapabilities {
  /** Agent supports client-provided MCP servers */
  clientServers?: boolean
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
}

/**
 * Session list capability configuration.
 * Reference: SDK's SessionListCapabilities (note: plural)
 * @experimental - This capability is not part of the spec yet
 */
export interface SessionListCapabilities {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
}

/**
 * Session resume capability configuration.
 * Reference: SDK's SessionResumeCapabilities (note: plural)
 * @experimental - This capability is not part of the spec yet
 */
export interface SessionResumeCapabilities {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
}

/**
 * Session fork capability configuration.
 * Reference: SDK's SessionForkCapabilities
 * @experimental - This capability is not part of the spec yet
 */
export interface SessionForkCapabilities {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
}

/**
 * Session capabilities supported by the agent.
 * Reference: acp::SessionCapabilities
 *
 * As a baseline, all Agents MUST support session/new, session/prompt,
 * session/cancel, and session/update.
 * Optionally, they MAY support other session methods by specifying
 * additional capabilities.
 */
export interface SessionCapabilities {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** @experimental Agent supports forking sessions via session/fork */
  fork?: SessionForkCapabilities | null
  /** @experimental Agent supports listing sessions via session/list */
  list?: SessionListCapabilities | null
  /** @experimental Agent supports resuming sessions via session/resume */
  resume?: SessionResumeCapabilities | null
}

/**
 * Capabilities supported by the agent.
 * Advertised during initialization to inform the client about
 * available features and content types.
 * Reference: acp::AgentCapabilities
 */
export interface AgentCapabilities {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Whether the agent supports session/load */
  loadSession?: boolean
  /** MCP capabilities supported by the agent */
  mcpCapabilities?: McpCapabilities
  /** Prompt capabilities supported by the agent */
  promptCapabilities?: PromptCapabilities
  /** Session capabilities supported by the agent */
  sessionCapabilities?: SessionCapabilities
}

// ============================================================================
// Session List/Load/Resume Types
// Reference: Zed's AgentSessionInfo, AgentSessionList in acp_thread/src/connection.rs
// SDK types: @agentclientprotocol/sdk SessionInfo, ListSessionsResponse
// ============================================================================

/**
 * Information about an existing session.
 * Returned by session/list and used for load/resume operations.
 * Reference: acp::SessionInfo (SDK), Zed's AgentSessionInfo
 * Note: SDK's SessionInfo has cwd as REQUIRED, but Zed's AgentSessionInfo has it optional
 * We follow SDK here for protocol compatibility
 */
export interface AgentSessionInfo {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Working directory for the session (required per SDK) */
  cwd: string
  /** Unique identifier for the session */
  sessionId: string
  /** Human-readable title for the session */
  title?: string | null
  /** ISO 8601 timestamp when the session was last updated */
  updatedAt?: string | null
}

/**
 * Request to list sessions.
 * Reference: acp::ListSessionsRequest
 */
export interface ListSessionsRequest {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Filter sessions by working directory */
  cwd?: string
  /** Pagination cursor for fetching more results */
  cursor?: string
}

/**
 * Response from listing sessions.
 * Reference: acp::ListSessionsResponse (SDK)
 */
export interface ListSessionsResponse {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Cursor for fetching the next page of results */
  nextCursor?: string | null
  /** Array of session info objects */
  sessions: AgentSessionInfo[]
}

/**
 * Request to load an existing session.
 * Reference: acp::LoadSessionRequest
 */
export interface LoadSessionRequest {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Session ID to load */
  sessionId: string
  /** Working directory for the session */
  cwd?: string
}

/**
 * Request to resume an existing session without replaying history.
 * Reference: acp::ResumeSessionRequest
 */
export interface ResumeSessionRequest {
  /** Reserved for extensibility */
  _meta?: Record<string, unknown> | null
  /** Session ID to resume */
  sessionId: string
  /** Working directory for the session */
  cwd?: string
}

// ============================================================================
// Model Selection Types (matches @agentclientprotocol/sdk)
// Reference: Zed's AgentModelSelector trait in acp_thread/src/connection.rs
// ============================================================================

/**
 * Information about a selectable model.
 * Matches ACP SDK's ModelInfo type.
 */
export interface ModelInfo {
  /** Unique identifier for the model */
  modelId: string
  /** Human-readable name of the model */
  name: string
  /** Optional description of the model */
  description?: string | null
}

/**
 * The set of models and the one currently active.
 * Matches ACP SDK's SessionModelState type.
 */
export interface SessionModelState {
  /** The set of models that the Agent can use */
  availableModels: ModelInfo[]
  /** The current model the Agent is using */
  currentModelId: string
}

// Settings
export interface ACPSettings {
  proxyUrl: string
  /** Auth token for remote access (sent via WebSocket subprotocol) */
  token?: string
  /** Working directory for the agent session */
  cwd?: string
}

export const DEFAULT_SETTINGS: ACPSettings = {
  proxyUrl: 'ws://localhost:9315/ws',
}
