/**
 * Terminal Channel Reducer — Pure reducer for `TerminalState`.
 *
 * @module channels-terminal/reducer
 */

import { ActionType } from '../common/actions.js';
import type { TerminalState, TerminalContentPart } from './state.js';
import type { TerminalAction } from '../action-origin.generated.js';
import { softAssertNever } from '../common/reducer-helpers.js';

/**
 * Pure reducer for terminal state. Handles all {@link TerminalAction} variants.
 */
export function terminalReducer(state: TerminalState, action: TerminalAction, log?: (msg: string) => void): TerminalState {
  switch (action.type) {
    case ActionType.TerminalData: {
      const content = [...state.content];
      const tail = content.length > 0 ? content[content.length - 1] : undefined;
      if (tail && tail.type === 'command' && !tail.isComplete) {
        content[content.length - 1] = { ...tail, output: tail.output + action.data };
      } else if (tail && tail.type === 'unclassified') {
        content[content.length - 1] = { ...tail, value: tail.value + action.data };
      } else {
        content.push({ type: 'unclassified', value: action.data });
      }
      return { ...state, content };
    }

    case ActionType.TerminalInput:
      // Side-effect-only: the server forwards to the pty.
      // No state change in the reducer.
      return state;

    case ActionType.TerminalResized:
      return { ...state, cols: action.cols, rows: action.rows };

    case ActionType.TerminalClaimed:
      return { ...state, claim: action.claim };

    case ActionType.TerminalTitleChanged:
      return { ...state, title: action.title };

    case ActionType.TerminalCwdChanged:
      return { ...state, cwd: action.cwd };

    case ActionType.TerminalExited:
      return { ...state, exitCode: action.exitCode };

    case ActionType.TerminalCleared:
      return { ...state, content: [] };

    case ActionType.TerminalCommandDetectionAvailable:
      return { ...state, supportsCommandDetection: true };

    case ActionType.TerminalCommandExecuted: {
      const part: TerminalContentPart = {
        type: 'command',
        commandId: action.commandId,
        commandLine: action.commandLine,
        output: '',
        timestamp: action.timestamp,
        isComplete: false,
      };
      return {
        ...state,
        content: [...state.content, part],
        supportsCommandDetection: true,
      };
    }

    case ActionType.TerminalCommandFinished: {
      const content = state.content.map(p => {
        if (p.type === 'command' && p.commandId === action.commandId) {
          return {
            ...p,
            isComplete: true as const,
            exitCode: action.exitCode,
            durationMs: action.durationMs,
          };
        }
        return p;
      });
      return { ...state, content };
    }

    default:
      softAssertNever(action, log);
      return state;
  }
}
