/**
 * ProxyModel Public API — the contract that stage authors write against.
 *
 * Stage authors import ONLY from this module. They never import mcpctl
 * internals. The framework wires up the services (llm, cache, log) so
 * stages can focus on content transformation.
 *
 * Two handler types:
 *   StageHandler  — pure content transformation (text in → text out)
 *   SessionController — method-level hooks with per-session state
 */

/** Fetches a system prompt by name, falling back to the provided default. */
export type SystemPromptFetcher = (name: string, fallback: string) => Promise<string>;

// ── Content Stage Contract ──────────────────────────────────────────

/**
 * A stage is the atomic unit of content transformation.
 * It receives content (from the previous stage or raw upstream)
 * and returns transformed content, optionally with drill-down sections.
 */
export interface StageHandler {
  (content: string, ctx: StageContext): Promise<StageResult>;
}

/** Services the framework provides to every stage. */
export interface StageContext {
  /** What kind of content is being processed */
  contentType: 'prompt' | 'toolResult' | 'resource';
  /** Identifier: prompt name, "server/tool", or resource URI */
  sourceName: string;
  /** Project this content belongs to */
  projectName: string;
  /** Current MCP session ID */
  sessionId: string;

  /** The original unmodified content (even if a previous stage changed it) */
  originalContent: string;

  // Platform services — stages use these, framework provides them
  llm: LLMProvider;
  cache: CacheProvider;
  log: StageLogger;

  /** Fetch a system prompt from mcpctl-system, with hardcoded fallback. */
  getSystemPrompt: SystemPromptFetcher;

  /** Stage-specific configuration from the proxymodel YAML */
  config: Record<string, unknown>;
}

export interface StageResult {
  /** The transformed content */
  content: string;
  /** Optional: section index for drill-down navigation */
  sections?: Section[];
  /** Optional: metrics, debug info, or other stage-specific data */
  metadata?: Record<string, unknown>;
}

/** A named section of content, addressable for drill-down. */
export interface Section {
  /** Addressable key (e.g. "token-handling", "flow1.function-1") */
  id: string;
  /** Human-readable label */
  title: string;
  /** Full section content (served when client drills down) */
  content: string;
  /** Nested sub-sections for hierarchical drill-down */
  children?: Section[];
}

// ── Session Controller Contract ─────────────────────────────────────

/**
 * A session controller manages method-level hooks and per-session state.
 * It intercepts JSON-RPC methods, registers virtual tools, and dispatches
 * notifications. The existing gated session system is a session controller.
 *
 * Not yet a public API — designed as an internal interface that can be
 * extracted later without rewriting existing code.
 */
export interface SessionController {
  /** Called once when session starts (initialize) */
  onInitialize?(ctx: SessionContext): Promise<InitializeHook>;

  /** Called when tools/list is requested — can modify the tool list */
  onToolsList?(tools: ToolDefinition[], ctx: SessionContext): Promise<ToolDefinition[]>;

  /** Called before a tool call is routed — can intercept and handle it */
  onToolCall?(toolName: string, args: unknown, ctx: SessionContext): Promise<InterceptResult | null>;

  /** Called after a tool call returns — can transform the result */
  onToolResult?(toolName: string, result: unknown, ctx: SessionContext): Promise<unknown>;

  /** Called when session ends */
  onClose?(ctx: SessionContext): Promise<void>;
}

export interface SessionContext extends StageContext {
  /** Per-session mutable state (persists across requests in a session) */
  state: Map<string, unknown>;

  /** Register a virtual tool that this controller handles */
  registerTool(tool: ToolDefinition, handler: VirtualToolHandler): void;

  /** Queue a notification to the MCP client */
  queueNotification(method: string, params?: unknown): void;

  /** Access the prompt index (for content selection) */
  prompts: PromptIndex;
}

export interface InitializeHook {
  /** Additional instructions to append to the initialize response */
  instructions?: string;
}

export interface InterceptResult {
  /** Replaces the normal tool call response */
  result: unknown;
  /** If true, emit tools/list_changed after this intercept */
  ungate?: boolean;
}

export type VirtualToolHandler = (args: unknown, ctx: SessionContext) => Promise<unknown>;

// ── Platform Service Interfaces ─────────────────────────────────────

/**
 * LLM provider exposed to stages. Wraps the internal ProviderRegistry
 * into a simple interface — stages don't care which model is running.
 */
export interface LLMProvider {
  /** Simple completion — send a prompt, get text back */
  complete(prompt: string, options?: LLMCompleteOptions): Promise<string>;
  /** Check if an LLM provider is configured and available */
  available(): boolean;
}

export interface LLMCompleteOptions {
  system?: string;
  maxTokens?: number;
}

/**
 * Content-addressed cache. The framework handles top-level stage caching,
 * but stages can also cache their own intermediate results.
 */
export interface CacheProvider {
  /** Get a cached value by key, or compute and cache it */
  getOrCompute(key: string, compute: () => Promise<string>): Promise<string>;
  /** Hash content for use as a cache key component */
  hash(content: string): string;
  /** Manually read from cache (returns null on miss) */
  get(key: string): Promise<string | null>;
  /** Manually write to cache */
  set(key: string, value: string): Promise<void>;
}

/** Structured logging tied to session/stage. */
export interface StageLogger {
  debug(msg: string): void;
  info(msg: string): void;
  warn(msg: string): void;
  error(msg: string): void;
}

// ── ProxyModel Definition ───────────────────────────────────────────

/** Parsed representation of a proxymodel YAML file. */
export interface ProxyModelDefinition {
  name: string;
  /** Session controller name. 'gate' = gated sessions, 'none' = no controller */
  controller: string;
  /** Config passed to the session controller */
  controllerConfig: Record<string, unknown>;
  /** Ordered pipeline of content stages */
  stages: StageDefinition[];
  /** Which content types this model processes */
  appliesTo: ContentType[];
  /** Whether the framework should cache stage results */
  cacheable: boolean;
  /** Where this model was loaded from */
  source: 'built-in' | 'local';
}

export interface StageDefinition {
  /** Stage name — resolved local → built-in */
  type: string;
  /** Stage-specific configuration passed as ctx.config */
  config: Record<string, unknown>;
}

export type ContentType = 'prompt' | 'toolResult' | 'resource';

// ── Supporting Types ────────────────────────────────────────────────

export interface ToolDefinition {
  name: string;
  description?: string;
  inputSchema?: Record<string, unknown> | unknown;
}

export interface PromptIndex {
  /** All available prompts for this project */
  list(): PromptIndexEntry[];
  /** Find prompts matching tags */
  match(tags: string[]): PromptIndexEntry[];
}

export interface PromptIndexEntry {
  name: string;
  summary: string;
  priority: number;
  tags: string[];
  content?: string;
}
