/**
 * Terminal Channel Actions — Mutations of an `ahp-terminal:` channel's state.
 *
 * @module channels-terminal/actions
 */

import { ActionType } from '../common/actions.js';
import type { URI } from '../common/state.js';
import type { TerminalClaim } from './state.js';

// ─── Terminal Actions ────────────────────────────────────────────────────────

/**
 * Terminal output data (pty → client direction).
 *
 * Appends `data` to the terminal's `content` in the reducer.
 *
 * `terminal/data` and `terminal/input` are intentionally separate actions
 * because standard write-ahead reconciliation is not safe for terminal I/O.
 * A pty is a stateful, mutable process — optimistically applying input or
 * predicting output would produce incorrect state. Instead, `terminal/input`
 * is a side-effect-only action (client → server → pty), and `terminal/data`
 * is server-authoritative output (pty → server → client).
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalDataAction {
  type: ActionType.TerminalData;
  /** Output data (may contain ANSI escape sequences) */
  data: string;
}

/**
 * Keyboard input sent to the terminal process (client → pty direction).
 *
 * This is a side-effect-only action: the server forwards the data to the
 * terminal's pty. The reducer treats this as a no-op since `terminal/data`
 * actions will reflect any resulting output.
 *
 * See `terminal/data` for why these two actions are kept separate.
 *
 * @category Terminal Actions
 * @version 1
 * @clientDispatchable
 */
export interface TerminalInputAction {
  type: ActionType.TerminalInput;
  /** Input data to send to the pty */
  data: string;
}

/**
 * Terminal dimensions changed.
 *
 * Dispatchable by clients to request a resize, or by the server to inform
 * clients of the actual terminal dimensions.
 *
 * @category Terminal Actions
 * @version 1
 * @clientDispatchable
 */
export interface TerminalResizedAction {
  type: ActionType.TerminalResized;
  /** Terminal width in columns */
  cols: number;
  /** Terminal height in rows */
  rows: number;
}

/**
 * Terminal claim changed. A client or session transfers ownership of the terminal.
 *
 * The server SHOULD reject if the dispatching client does not currently hold
 * the claim.
 *
 * @category Terminal Actions
 * @version 1
 * @clientDispatchable
 */
export interface TerminalClaimedAction {
  type: ActionType.TerminalClaimed;
  /** The new claim */
  claim: TerminalClaim;
}

/**
 * Terminal title changed.
 *
 * Fired by the server when the terminal process updates its title (e.g. via
 * escape sequences), or dispatched by a client to rename a terminal.
 *
 * @category Terminal Actions
 * @version 1
 * @clientDispatchable
 */
export interface TerminalTitleChangedAction {
  type: ActionType.TerminalTitleChanged;
  /** New terminal title */
  title: string;
}

/**
 * Terminal working directory changed.
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalCwdChangedAction {
  type: ActionType.TerminalCwdChanged;
  /** New working directory */
  cwd: URI;
}

/**
 * Terminal process exited.
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalExitedAction {
  type: ActionType.TerminalExited;
  /** Process exit code. `undefined` if the process was killed without an exit code. */
  exitCode?: number;
}

/**
 * Terminal scrollback buffer cleared.
 *
 * @category Terminal Actions
 * @version 1
 * @clientDispatchable
 */
export interface TerminalClearedAction {
  type: ActionType.TerminalCleared;
}

/**
 * Shell integration has loaded and the terminal now supports command
 * detection. The server dispatches this when shell integration becomes
 * available (which may happen asynchronously after the terminal is created).
 *
 * Clients MUST NOT assume command detection is available until this action
 * (or `terminal/commandExecuted`) has been received.
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalCommandDetectionAvailableAction {
  type: ActionType.TerminalCommandDetectionAvailable;
}

/**
 * A command has been submitted to the shell and is now executing.
 * All subsequent `terminal/data` actions (until the matching
 * `terminal/commandFinished`) constitute this command's output.
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalCommandExecutedAction {
  type: ActionType.TerminalCommandExecuted;
  /**
   * Stable identifier for this command, scoped to the terminal URI.
   * Allows correlating `commandExecuted` → `commandFinished` pairs.
   */
  commandId: string;
  /** The command line text that was submitted */
  commandLine: string;
  /**
   * Unix timestamp (ms) of when the command started executing, as measured
   * on the server.
   */
  timestamp: number;
}

/**
 * A command has finished executing.
 *
 * The sequence of `terminal/data` actions between the preceding
 * `terminal/commandExecuted` (same `commandId`) and this action constitutes
 * the complete output of the command.
 *
 * @category Terminal Actions
 * @version 1
 */
export interface TerminalCommandFinishedAction {
  type: ActionType.TerminalCommandFinished;
  /** Matches the `commandId` from the corresponding `commandExecuted` */
  commandId: string;
  /** Shell exit code. `undefined` if the shell did not report one. */
  exitCode?: number;
  /**
   * Wall-clock duration of the command in milliseconds, as measured by the
   * shell integration script on the server side.
   */
  durationMs?: number;
}
