/**
 * Session Channel Commands — `createSession`, `disposeSession`, `fetchTurns`,
 * and `completions`. Most target a specific `ahp-session:` URI.
 *
 * @module channels-session/commands
 */

import type { URI } from '../common/state.js';
import type { BaseParams } from '../common/commands.js';
import type { ModelSelection } from '../channels-root/state.js';
import type {
  Turn,
  SessionActiveClient,
  MessageAttachment,
  AgentSelection,
} from './state.js';

// ─── createSession ───────────────────────────────────────────────────────────

/**
 * Creates a new session with the specified agent provider.
 *
 * If the session URI already exists, the server MUST return an error with code
 * `-32003` (`SessionAlreadyExists`).
 *
 * After creation, the client should subscribe to the session URI to receive state
 * updates. The server also broadcasts a `root/sessionAdded` notification to all
 * clients.
 *
 * @category Commands
 * @method createSession
 * @direction Client → Server
 * @messageType Request
 * @version 1
 * @example
 * ```jsonc
 * // Client → Server
 * { "jsonrpc": "2.0", "id": 2, "method": "createSession",
 *   "params": { "channel": "ahp-session:/<uuid>", "provider": "copilot", "model": "gpt-4o" } }
 *
 * // Server → Client (success)
 * { "jsonrpc": "2.0", "id": 2, "result": null }
 *
 * // Server → Client (failure — provider not found)
 * { "jsonrpc": "2.0", "id": 2, "error": { "code": -32002, "message": "No agent for provider" } }
 *
 * // Server → Client (failure — session already exists)
 * { "jsonrpc": "2.0", "id": 2, "error": { "code": -32003, "message": "Session already exists" } }
 * ```
 */
/**
 * Identifies a source session and turn to fork from.
 *
 * When provided in `createSession`, the server populates the new session with
 * content from the source session up to and including the response of the
 * specified turn.
 */
export interface SessionForkSource {
  /** URI of the existing session to fork from */
  session: URI;
  /** Turn ID in the source session; content up to and including this turn's response is copied */
  turnId: string;
}

export interface CreateSessionParams extends BaseParams {
  /** Session URI (client-chosen, e.g. `ahp-session:/<uuid>`) */
  channel: URI;
  /** Agent provider ID */
  provider?: string;
  /** Model selection (ID and optional model-specific configuration) */
  model?: ModelSelection;
  /**
   * Initial custom agent selection for the new session.
   *
   * Omit to start the session with no custom agent selected (provider default).
   */
  agent?: AgentSelection;
  /** Working directory for the session */
  workingDirectory?: URI;
  /**
   * Fork from an existing session. The new session is populated with content
   * from the source session up to and including the specified turn's response.
   */
  fork?: SessionForkSource;
  /**
   * Agent-specific configuration values collected via `resolveSessionConfig`.
   * Keys and values correspond to the schema returned by the server.
   */
  config?: Record<string, unknown>;
  /**
   * Eagerly claim the active client role for the new session.
   *
   * When provided, the server initializes the session with this client as the
   * active client, equivalent to dispatching a `session/activeClientChanged`
   * action immediately after creation. The `clientId` MUST match the
   * `clientId` the creating client supplied in `initialize`.
   */
  activeClient?: SessionActiveClient;
}

// ─── disposeSession ──────────────────────────────────────────────────────────

/**
 * Disposes a session and cleans up server-side resources.
 *
 * The server broadcasts a `root/sessionRemoved` notification to all clients.
 *
 * @category Commands
 * @method disposeSession
 * @direction Client → Server
 * @messageType Request
 * @version 1
 */
export interface DisposeSessionParams extends BaseParams {}

// ─── fetchTurns ──────────────────────────────────────────────────────────────

/**
 * Fetches historical turns for a session. Used for lazy loading of conversation
 * history.
 *
 * @category Commands
 * @method fetchTurns
 * @direction Client → Server
 * @messageType Request
 * @version 1
 * @example
 * ```jsonc
 * // Client → Server (fetch the 20 most recent turns)
 * { "jsonrpc": "2.0", "id": 8, "method": "fetchTurns",
 *   "params": { "channel": "ahp-session:/<uuid>", "limit": 20 } }
 *
 * // Server → Client
 * { "jsonrpc": "2.0", "id": 8, "result": {
 *   "turns": [ { "id": "t1", ... }, { "id": "t2", ... } ],
 *   "hasMore": true
 * }}
 *
 * // Client → Server (fetch 20 turns before t1)
 * { "jsonrpc": "2.0", "id": 9, "method": "fetchTurns",
 *   "params": { "channel": "ahp-session:/<uuid>", "before": "t1", "limit": 20 } }
 * ```
 */
export interface FetchTurnsParams extends BaseParams {
  /** Session URI */
  channel: URI;
  /** Turn ID to fetch before (exclusive). Omit to fetch from the most recent turn. */
  before?: string;
  /** Maximum number of turns to return. Server MAY impose its own upper bound. */
  limit?: number;
}

/**
 * Result of the `fetchTurns` command.
 */
export interface FetchTurnsResult {
  /** The requested turns, ordered oldest-first */
  turns: Turn[];
  /** Whether more turns exist before the returned range */
  hasMore: boolean;
}

// ─── completions ─────────────────────────────────────────────────────────────

/**
 * The kind of completion items being requested.
 *
 * @category Commands
 */
export const enum CompletionItemKind {
  /**
   * Completions for the text of a {@link Message} the user is composing.
   * Each returned item carries an attachment that gets associated with the
   * message when accepted.
   */
  UserMessage = 'userMessage',
}

/**
 * Requests completion items for a partially-typed input (e.g. a user message
 * the user is currently composing). Used to power `@`-mention pickers,
 * file/symbol references, and similar inline-completion experiences.
 *
 * Servers SHOULD treat this command as best-effort and return promptly. The
 * client SHOULD debounce calls to avoid flooding the server with requests on
 * every keystroke.
 *
 * @category Commands
 * @method completions
 * @direction Client → Server
 * @messageType Request
 * @version 1
 * @example
 * ```jsonc
 * // User has typed "look at @foo" and the cursor is just after "@foo".
 * // Client → Server
 * { "jsonrpc": "2.0", "id": 12, "method": "completions",
 *   "params": { "kind": "userMessage", "channel": "ahp-session:/<uuid>",
 *               "text": "look at @foo", "offset": 12 } }
 *
 * // Server → Client
 * { "jsonrpc": "2.0", "id": 12, "result": {
 *   "items": [
 *     {
 *       "insertText": "@foo.ts",
 *       "rangeStart": 8,
 *       "rangeEnd": 12,
 *       "attachment": {
 *         "type": "resource",
 *         "label": "foo.ts",
 *         "displayKind": "document",
 *         "uri": "file:///workspace/foo.ts"
 *       }
 *     }
 *   ]
 * }}
 * ```
 */
export interface CompletionsParams extends BaseParams {
  /** What kind of completion is being requested. */
  kind: CompletionItemKind;
  /** The session URI the completion is being requested for. */
  channel: URI;
  /**
   * The complete text of the input being completed (e.g. the full user
   * message text typed so far).
   */
  text: string;
  /**
   * The character offset within `text` at which the completion is requested,
   * measured in UTF-16 code units. MUST satisfy `0 <= offset <= text.length`.
   */
  offset: number;
}

/**
 * A single completion item returned by the `completions` command.
 *
 * When the user accepts an item, the client SHOULD:
 * 1. Replace the range `[rangeStart, rangeEnd)` in the input with `insertText`
 *    (or insert `insertText` at the cursor when the range is omitted).
 * 2. Associate the item's `attachment` with the resulting {@link Message}.
 *
 * @category Commands
 */
export interface CompletionItem {
  /**
   * The text inserted into the input when this item is accepted.
   */
  insertText: string;

  /**
   * If defined, the start of the range in the input's `text` that is replaced
   * by `insertText`. The range is the half-open interval
   * `[rangeStart, rangeEnd)` of character offsets, measured in UTF-16 code
   * units.
   *
   * When omitted, the client SHOULD insert `insertText` at the cursor.
   *
   * Note: this range refers to positions in the *current* input. The
   * attachment's own `rangeStart`/`rangeEnd` (when present) refer to
   * positions in the final {@link Message.text} after the item is
   * accepted.
   */
  rangeStart?: number;

  /**
   * The end of the range in the input's `text` that is replaced by
   * `insertText`. See {@link rangeStart}.
   */
  rangeEnd?: number;

  /**
   * The attachment associated with this completion item.
   */
  attachment: MessageAttachment;
}

/**
 * Result of the `completions` command.
 */
export interface CompletionsResult {
  /** The completion items, in the order the server suggests displaying them. */
  items: CompletionItem[];
}
