import type {
  ChatAttachment,
  ChatDriverResult,
  ChatMessage,
  ChatToolDefinition,
} from '@genesislcap/foundation-ai';
import type { AgentConfig } from '../../config/config';
import type { DiagnosticEntry } from '../../state/persistence/diagnostics';
import type { InteractionContext } from '../../types/interaction-context';
import type { TurnSnapshot } from '../chat-driver/chat-driver';

/** @internal */
export interface AllAgentSummary {
  name: string;
  description: string;
  tools: ChatToolDefinition[];
}

/**
 * Common interface implemented by both `ChatDriver` (single-agent) and
 * `OrchestratingDriver` (multi-agent). `FoundationAiAssistant` depends only
 * on this interface — the concrete class is chosen at startup based on how
 * many agents are configured.
 *
 * Extends `EventTarget` so consumers can subscribe to `history-updated` events
 * without knowing the concrete implementation.
 *
 * @beta
 */
export interface AiDriver extends EventTarget {
  /**
   * Send a user message and run the tool loop to completion.
   */
  sendMessage(input: string, attachments?: ChatAttachment[]): Promise<ChatDriverResult>;

  /**
   * Continue the tool loop from the current history without appending a new
   * user message. Used by `OrchestratingDriver` on agent handoffs — the
   * handoff context is already in history; `transientPrimer` is injected as
   * an invisible one-shot message for this call only.
   */
  continueFromHistory(transientPrimer?: ChatMessage[]): Promise<ChatDriverResult>;

  /**
   * Resolve a pending blocking interaction with the given result.
   */
  resolveInteraction(interactionId: string, result: unknown): void;

  /**
   * The live {@link InteractionContext} for a pending interaction (GENC-1390), or
   * `undefined` if the interaction is resolved/evicted or the driver owns no
   * interactions. Pierced by `AiChatInteractionWrapper` to build the widget's
   * `interaction` descriptor. Optional — only interaction-owning drivers implement it.
   */
  getInteractionContext?(interactionId: string): InteractionContext | undefined;

  /**
   * Seed the driver's message history (called on state restore / pop-in).
   */
  loadHistory(messages: ChatMessage[]): void;

  /**
   * Prime per-agent restored state for a session being rehydrated. Each entry
   * (keyed by agent name) is handed to that agent's `onActivate`/`init` as
   * `ctx.restored` on its next activation, then consumed. Optional — only
   * multi-agent drivers that own agent activation implement it.
   */
  primeRestoredAgentState?(snapshots: Record<string, unknown>): void;

  /**
   * Return the full, unredacted conversation history.
   */
  getRawHistory?(): readonly ChatMessage[];

  /**
   * The live `AgentConfig` currently active in the driver — the instance whose
   * `onActivate` ran, so its `serialize`/`getDebugSnapshot` closures hold live
   * state. Prefer this over looking the agent up in the host's `agents` array,
   * which may mint fresh, never-activated configs. Optional — only drivers that
   * retain the active config implement it.
   */
  getActiveAgent?(): AgentConfig | undefined;

  /**
   * Destructively compact older conversation turns into a single
   * `compacted-summary` message (GENC-1351 §5.7), summarizing them via the
   * default provider's one-shot `prompt()`. Atomic: history changes only on
   * success. Resolves to the created summary message, or `null` when there is
   * nothing worth compacting or the provider cannot summarize. Optional — only
   * drivers that own history implement it.
   */
  compact?(): Promise<ChatMessage | null>;

  /**
   * Whether `compact()` would compact something right now — a summarizable run of
   * older turns exists behind a clean boundary. The UI gates its "Compact"
   * affordance on this, so the button reflects the exact history `compact()` acts
   * on (GENC-1351). Optional — only history-owning drivers implement it.
   */
  canCompact?(): boolean;

  /**
   * Returns true if the driver is currently processing a request.
   */
  isBusy(): boolean;

  /**
   * Get query suggestions from the AI.
   */
  getSuggestions(
    history: ChatMessage[],
    prompt: string,
    count: number,
    allAgentInfo?: AllAgentSummary[],
  ): Promise<string[]>;

  /**
   * Per-LLM-call snapshots — what the model saw each turn (prompt, tools,
   * agent state). Used by the host's debug-log exporter. Optional because the
   * interface is implemented by both leaf and orchestrating drivers; the
   * orchestrator just delegates to its inner `ChatDriver`.
   */
  getTurnSnapshots?(): ReadonlyArray<TurnSnapshot>;

  /**
   * Diagnostic-log entries harvested from resolved interactions (e.g. a server-side ChatDriver's
   * collated debug log, returned on `InteractionResult.diagnostics`). The host folds these into its
   * debug log. Optional for the same leaf/orchestrator reason as `getTurnSnapshots`.
   * (GENC-1461 unified diagnostics.)
   */
  getExternalDiagnostics?(): ReadonlyArray<DiagnosticEntry>;

  /**
   * Name of the AI provider used on the most recent turn. Falls back to the
   * registry's default name when no turn has run yet.
   *
   * @beta
   */
  getActiveProviderName(): string;

  /**
   * Tear down the driver, aborting any in-flight provider request. Called by
   * the host when it swaps in a replacement driver. Optional because not every
   * implementation needs teardown; the host invokes it when present.
   */
  dispose?(): void | Promise<void>;

  /**
   * Stop the current turn in response to a user "stop" action. Aborts the
   * in-flight provider request; a tool already executing runs to completion and
   * the loop stops at the next boundary. The driver stays usable afterwards.
   * Optional; the host wires the stop button to it when present.
   */
  cancel?(): void;
}
