/**
 * Shared ACP session-update → normalized AgentEvent mapping.
 *
 * Extracted verbatim (v2.6 Phase 2) from `AcpStreamContext.handleSessionUpdate`
 * in `acp-dispatch.ts` so the warm ACP backend (`backends/warm-acp.ts`) and the
 * one-shot dispatch share ONE mapping. The one-shot path translates the returned
 * events into broker frames itself (preserving its prior behavior byte-for-byte);
 * the warm backend forwards them to the dispatcher's `ctx.onEvent` exactly like
 * the opencode-server backend does. No I/O, no broker — pure, so it's unit-testable.
 *
 * Spec: openspec/changes/v2-6-persistent-agent-sessions/design.md §2b.
 */
import type { SessionNotification } from '@agentclientprotocol/sdk';
import type { AgentEvent } from './agent-backend.js';
import { type AcpToolSnapshot, mergeToolSnapshot } from './acp-tool-snapshot.js';

/**
 * Map one ACP `session/update` notification to zero-or-more normalized AgentEvents.
 *
 * `priorSnapshots` is the caller-owned tool-call snapshot accumulator (toolCallId →
 * snapshot). For `tool_call` / `tool_call_update` the merged snapshot is written
 * back into it (mutated in place, mirroring `AcpStreamContext.handleToolUpdate`)
 * so a later `tool_call_update` merges over the earlier `tool_call`. Pass an empty
 * Map for a stateless single call.
 *
 * Returns an array (never throws) so the caller can splat it onto `onEvent`.
 */
export function mapSessionUpdate(
  params: SessionNotification,
  priorSnapshots: Map<string, AcpToolSnapshot> = new Map(),
): AgentEvent[] {
  const update = params.update;
  switch (update.sessionUpdate) {
    case 'agent_message_chunk': {
      const content = update.content;
      if (content.type === 'text' && 'text' in content) {
        return [{ type: 'text', text: (content as { text: string }).text }];
      }
      return [];
    }
    case 'agent_thought_chunk': {
      const content = update.content;
      if (content.type === 'text' && 'text' in content) {
        return [{ type: 'reasoning', text: (content as { text: string }).text }];
      }
      return [];
    }
    case 'tool_call': {
      const snapshot = mergeToolSnapshot(update.toolCallId, update, priorSnapshots.get(update.toolCallId));
      priorSnapshots.set(update.toolCallId, snapshot);
      return [{ type: 'tool_call', toolCall: snapshot }];
    }
    case 'tool_call_update': {
      const snapshot = mergeToolSnapshot(update.toolCallId, update, priorSnapshots.get(update.toolCallId));
      priorSnapshots.set(update.toolCallId, snapshot);
      return [{ type: 'tool_update', toolCall: snapshot }];
    }
    case 'available_commands_update': {
      const commands = update.availableCommands.map((cmd) => ({
        name: cmd.name,
        description: cmd.description ?? undefined,
      }));
      return [{ type: 'commands', commands }];
    }
    default:
      return [];
  }
}
