/**
 * ACP tool snapshot merge + wire mapping — lifted from Paseo acp-agent.ts patterns.
 * Stable toolCallId, merge on tool_call_update, status lifecycle for UI + DB.
 */
import type { ToolCall, ToolCallUpdate, ToolCallStatus, ToolKind } from '@agentclientprotocol/sdk';

export type AcpToolLifecycleStatus = 'running' | 'completed' | 'failed' | 'canceled';

export interface AcpToolSnapshot {
  toolCallId: string;
  title: string;
  kind?: ToolKind | null;
  status?: ToolCallStatus | null;
  rawInput?: unknown;
  rawOutput?: unknown;
}

export interface AcpWireMeta {
  status: AcpToolLifecycleStatus;
  kind?: string | null;
  title?: string;
  output?: unknown;
  error?: string;
}


export function mergeToolSnapshot(
  toolCallId: string,
  update: ToolCall | ToolCallUpdate,
  previous?: AcpToolSnapshot,
): AcpToolSnapshot {
  return {
    toolCallId,
    title: update.title ?? previous?.title ?? toolCallId,
    kind: update.kind ?? previous?.kind ?? null,
    status: update.status ?? previous?.status ?? null,
    rawInput: update.rawInput !== undefined ? update.rawInput : previous?.rawInput,
    rawOutput: update.rawOutput !== undefined ? update.rawOutput : previous?.rawOutput,
  };
}

export function mapToolLifecycleStatus(
  status: ToolCallStatus | null | undefined,
  rawOutput?: unknown,
): AcpToolLifecycleStatus {
  if (rawOutput === 'canceled') return 'canceled';
  switch (status) {
    case 'completed':
      return 'completed';
    case 'failed':
      return 'failed';
    case 'pending':
    case 'in_progress':
    default:
      return 'running';
  }
}

function readErrorMessage(rawOutput: unknown): string | undefined {
  if (typeof rawOutput === 'string' && rawOutput.trim()) return rawOutput;
  if (rawOutput && typeof rawOutput === 'object' && !Array.isArray(rawOutput)) {
    const rec = rawOutput as Record<string, unknown>;
    const msg = rec.message ?? rec.error ?? rec.reason;
    if (typeof msg === 'string' && msg.trim()) return msg;
  }
  return undefined;
}

function asRecord(value: unknown): Record<string, unknown> {
  if (value && typeof value === 'object' && !Array.isArray(value)) {
    return value as Record<string, unknown>;
  }
  return {};
}

export function snapshotToWireToolCall(snapshot: AcpToolSnapshot): {
  id: string;
  name: string;
  args: Record<string, unknown>;
} {
  const lifecycle = mapToolLifecycleStatus(snapshot.status, snapshot.rawOutput);
  const input = asRecord(snapshot.rawInput);
  const error = lifecycle === 'failed' ? readErrorMessage(snapshot.rawOutput) : undefined;
  const meta: AcpWireMeta = {
    status: lifecycle,
    kind: snapshot.kind ?? null,
    title: snapshot.title,
    ...(snapshot.rawOutput !== undefined ? { output: snapshot.rawOutput } : {}),
    ...(error ? { error } : {}),
  };
  return {
    id: snapshot.toolCallId,
    name: String(snapshot.kind ?? snapshot.title),
    args: { ...input, _acp: meta },
  };
}

export function snapshotToPartPayload(snapshot: AcpToolSnapshot): {
  id: string;
  name: string;
  args: Record<string, unknown>;
} {
  const wire = snapshotToWireToolCall(snapshot);
  return { id: wire.id, name: wire.name, args: wire.args };
}

export function synthesizeCanceledSnapshots(snapshots: Iterable<AcpToolSnapshot>): AcpToolSnapshot[] {
  const out: AcpToolSnapshot[] = [];
  for (const snapshot of snapshots) {
    if (mapToolLifecycleStatus(snapshot.status) === 'running') {
      out.push({ ...snapshot, status: 'failed', rawOutput: snapshot.rawOutput ?? 'canceled' });
    }
  }
  return out;
}
