import type { ServerWebSocket } from "bun";
import type {
  BackendType,
  BrowserIncomingMessage,
  PermissionRequest,
  SessionState,
  BufferedBrowserEvent,
  QueuedMessage,
} from "./session-types.js";
import type { CodexAdapter } from "./codex-adapter.js";

export interface CLISocketData {
  kind: "cli";
  sessionId: string;
  /** Set on CLI reconnect: the UUID of the last message the CLI sent before disconnect. */
  lastRequestId?: string;
}

export interface BrowserSocketData {
  kind: "browser";
  sessionId: string;
  subscribed?: boolean;
  lastAckSeq?: number;
}

export interface TerminalSocketData {
  kind: "terminal";
  terminalId: string;
}

export type SocketData = CLISocketData | BrowserSocketData | TerminalSocketData;

/** A message sent from server to CLI, stored for replay on reconnection. */
export interface SentMessage {
  /** Monotonic sequence number assigned at send time. */
  seq: number;
  /** The raw NDJSON string sent to the CLI. */
  data: string;
}

/** Tracks a pending control_request sent to CLI that expects a control_response. */
export interface PendingControlRequest {
  subtype: string;
  resolve: (response: unknown) => void;
}

export interface Session {
  id: string;
  backendType: BackendType;
  cliSocket: ServerWebSocket<SocketData> | null;
  codexAdapter: CodexAdapter | null;
  browserSockets: Set<ServerWebSocket<SocketData>>;
  state: SessionState;
  pendingPermissions: Map<string, PermissionRequest>;
  pendingControlRequests: Map<string, PendingControlRequest>;
  messageHistory: BrowserIncomingMessage[];
  pendingMessages: string[];
  nextEventSeq: number;
  eventBuffer: BufferedBrowserEvent[];
  lastAckSeq: number;
  processedClientMessageIds: string[];
  processedClientMessageIdSet: Set<string>;
  messageQueue: QueuedMessage[];
  queuePaused: boolean;
  /** Interval timer for sending keep_alive messages to the CLI WebSocket. */
  keepAliveInterval: ReturnType<typeof setInterval> | null;
  /** Circular buffer of messages sent to the CLI (for replay on reconnect). */
  sentMessageBuffer: SentMessage[];
  /** Monotonic counter of messages written to sentMessageBuffer. */
  sentMessageSeq: number;
  /** Maps CLI message UUID → sentMessageSeq at time of receipt (for replay correlation). */
  cliMessageSeqMap: Map<string, number>;
  /** Set of file paths modified by this session (for conflict detection). */
  modifiedFiles: Set<string>;
}

export type GitSessionKey =
  | "git_branch"
  | "is_worktree"
  | "is_containerized"
  | "repo_root"
  | "git_ahead"
  | "git_behind";

export function makeDefaultState(
  sessionId: string,
  backendType: BackendType = "claude",
): SessionState {
  return {
    session_id: sessionId,
    backend_type: backendType,
    model: "",
    cwd: "",
    tools: [],
    permissionMode: "default",
    claude_code_version: "",
    mcp_servers: [],
    agents: [],
    slash_commands: [],
    skills: [],
    total_cost_usd: 0,
    num_turns: 0,
    context_used_percent: 0,
    input_tokens: 0,
    output_tokens: 0,
    cache_read_tokens: 0,
    cache_creation_tokens: 0,
    context_window: 0,
    is_compacting: false,
    git_branch: "",
    is_worktree: false,
    is_containerized: false,
    repo_root: "",
    git_ahead: 0,
    git_behind: 0,
    total_lines_added: 0,
    total_lines_removed: 0,
    background_tasks: [],
    teammates: [],
  };
}
