/**
 * Adapter dispatcher for the inference proxy.
 *
 * `getAdapter(type)` returns the right adapter instance for an Llm's `type`
 * column. Adapters are cached per-type — they carry no per-request state.
 * The caller (the infer route) supplies the resolved API key + request body
 * through `InferContext`, so a single adapter instance serves every Llm of
 * that type.
 */
import type { LlmAdapter, AdapterDeps } from './types.js';
import { OpenAiPassthroughAdapter } from './adapters/openai-passthrough.js';
import { AnthropicAdapter } from './adapters/anthropic.js';

export class UnsupportedProviderError extends Error {
  constructor(type: string) {
    super(`Unsupported LLM provider: ${type}`);
    this.name = 'UnsupportedProviderError';
  }
}

export class LlmAdapterRegistry {
  private readonly cache = new Map<string, LlmAdapter>();

  constructor(private readonly deps: AdapterDeps = {}) {}

  get(type: string): LlmAdapter {
    const cached = this.cache.get(type);
    if (cached !== undefined) return cached;
    const adapter = this.build(type);
    this.cache.set(type, adapter);
    return adapter;
  }

  private build(type: string): LlmAdapter {
    switch (type) {
      case 'openai':
      case 'vllm':
      case 'deepseek':
      case 'ollama':
        return new OpenAiPassthroughAdapter(type, this.deps);
      case 'anthropic':
        return new AnthropicAdapter(this.deps);
      case 'gemini-cli':
        // Intentionally deferred — gemini-cli requires the binary on the mcpd
        // pod filesystem and subprocess lifecycle management. Flagged as
        // homelab-only in the plan; not landing in this phase.
        throw new UnsupportedProviderError(`${type} (subprocess providers are not supported in the proxy yet)`);
      default:
        throw new UnsupportedProviderError(type);
    }
  }
}
