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

import { ActionType } from '../common/actions.js';
import type { ErrorInfo } from '../common/state.js';
import type { ChangesetFile, ChangesetOperation } from './state.js';
import { ChangesetStatus } from './state.js';
import type { ChangesetOperationStatus } from './state.js';

// ─── Changeset Actions ───────────────────────────────────────────────────────

/**
 * The {@link ChangesetState.status} for this changeset transitioned (e.g.
 * `computing → ready`). The error payload is set together with `status`
 * whenever it transitions to {@link ChangesetStatus.Error | Error}.
 *
 * @category Changeset Actions
 * @version 2
 */
export interface ChangesetStatusChangedAction {
  type: ActionType.ChangesetStatusChanged;
  /** New computation lifecycle status. */
  status: ChangesetStatus;
  /** Cause when `status === ChangesetStatus.Error`; otherwise omitted. */
  error?: ErrorInfo;
}

/**
 * Upsert a {@link ChangesetFile} in the changeset — adds a new entry, or
 * replaces an existing one identified by {@link ChangesetFile.id}.
 *
 * @category Changeset Actions
 * @version 2
 */
export interface ChangesetFileSetAction {
  type: ActionType.ChangesetFileSet;
  /** The new or replacement file entry. */
  file: ChangesetFile;
}

/**
 * Remove a {@link ChangesetFile} from the changeset by its id.
 *
 * Typically dispatched when a file is reverted, staged out, or otherwise
 * no longer in scope (e.g. a renamed file is replaced by a new entry).
 *
 * @category Changeset Actions
 * @version 2
 */
export interface ChangesetFileRemovedAction {
  type: ActionType.ChangesetFileRemoved;
  /** The {@link ChangesetFile.id} of the file to remove. */
  fileId: string;
}

/**
 * The set of operations available on this changeset changed. Full
 * replacement semantics: `operations` replaces the previous list (or
 * removes it entirely when `operations` is `undefined`).
 *
 * @category Changeset Actions
 * @version 2
 */
export interface ChangesetOperationsChangedAction {
  type: ActionType.ChangesetOperationsChanged;
  /** Updated operation list. Pass `undefined` to clear all operations. */
  operations: ChangesetOperation[] | undefined;
}

/**
 * The {@link ChangesetOperation.status} for a single operation transitioned
 * (e.g. `idle → running → idle`, or `running → error`). The error payload
 * is set together with `status` whenever it transitions to
 * {@link ChangesetOperationStatus.Error | Error}, and cleared on any other
 * transition.
 *
 * Targets one operation by its {@link ChangesetOperation.id}. If no
 * operation with that id is currently present in the changeset, the action
 * is a no-op. Use {@link ChangesetOperationsChangedAction} to add, remove,
 * or otherwise replace the operation list itself.
 *
 * @category Changeset Actions
 * @version 3
 */
export interface ChangesetOperationStatusChangedAction {
  type: ActionType.ChangesetOperationStatusChanged;
  /** The {@link ChangesetOperation.id} whose status changed. */
  operationId: string;
  /** New execution status. */
  status: ChangesetOperationStatus;
  /** Cause when `status === ChangesetOperationStatus.Error`; otherwise omitted. */
  error?: ErrorInfo;
}

/**
 * Drop every file from the changeset.
 *
 * Two cases use this:
 * 1. The underlying source moved (branch switched, fork point invalidated,
 *    …) and the server is recomputing from scratch — subsequent
 *    {@link ChangesetFileSetAction} entries will repopulate it.
 * 2. The owning session has ended and the URI is becoming
 *    un-subscribable — the server will unsubscribe all clients shortly
 *    after dispatching this action.
 *
 * Clients SHOULD release any references on receipt and SHOULD NOT
 * distinguish the two cases from the action alone — instead, react to
 * the corresponding session-level lifecycle signal (e.g.
 * `root/sessionRemoved`) for the "going away" case.
 *
 * @category Changeset Actions
 * @version 2
 */
export interface ChangesetClearedAction {
  type: ActionType.ChangesetCleared;
}
