import type { ChatRequestDto, ChatResponseDto, EmbedRequestDto, EmbedResponseDto } from "../dto";

/**
 * Base configuration for all LLM providers.
 * Provider-specific implementations can extend this interface.
 */
export interface LlmProviderConfig {
  /**
   * Provider endpoint URL (e.g., "http://localhost:11434" for Ollama)
   */
  endpoint: string;

  /**
   * Request timeout in milliseconds
   * @default 30000
   */
  timeout?: number;

  /**
   * Additional provider-specific configuration
   */
  [key: string]: unknown;
}

/**
 * Health status returned by provider health checks
 */
export interface LlmProviderHealthStatus {
  /**
   * Whether the provider is healthy and ready to accept requests
   */
  healthy: boolean;

  /**
   * Provider name (e.g., "ollama", "claude", "openai")
   */
  provider: string;

  /**
   * Provider endpoint being checked
   */
  endpoint?: string;

  /**
   * Error message if unhealthy
   */
  error?: string;

  /**
   * Available models (optional, for providers that support listing)
   */
  models?: string[];

  /**
   * Additional metadata about the health check
   */
  metadata?: Record<string, unknown>;
}

/**
 * Provider type discriminator for runtime type checking
 */
export type LlmProviderType = "ollama" | "claude" | "openai";

/**
 * Abstract interface that all LLM providers must implement.
 * Supports multiple LLM backends (Ollama, Claude, OpenAI, etc.)
 *
 * @example
 * ```typescript
 * class OllamaProvider implements LlmProviderInterface {
 *   readonly name = "ollama";
 *   readonly type = "ollama";
 *
 *   constructor(config: OllamaProviderConfig) {
 *     // Initialize provider
 *   }
 *
 *   async initialize(): Promise<void> {
 *     // Setup provider connection
 *   }
 *
 *   async chat(request: ChatRequestDto): Promise<ChatResponseDto> {
 *     // Implement chat completion
 *   }
 *
 *   // ... implement other methods
 * }
 * ```
 */
export interface LlmProviderInterface {
  /**
   * Human-readable provider name (e.g., "Ollama", "Claude", "OpenAI")
   */
  readonly name: string;

  /**
   * Provider type discriminator for runtime type checking
   */
  readonly type: LlmProviderType;

  /**
   * Initialize the provider connection and resources.
   * Called once during provider instantiation.
   *
   * @throws {Error} If initialization fails
   */
  initialize(): Promise<void>;

  /**
   * Check if the provider is healthy and ready to accept requests.
   *
   * @returns Health status with provider details
   */
  checkHealth(): Promise<LlmProviderHealthStatus>;

  /**
   * List all available models from this provider.
   *
   * @returns Array of model names
   * @throws {Error} If provider is not initialized or request fails
   */
  listModels(): Promise<string[]>;

  /**
   * Perform a synchronous chat completion.
   *
   * @param request - Chat request with messages and configuration
   * @returns Complete chat response
   * @throws {Error} If provider is not initialized or request fails
   */
  chat(request: ChatRequestDto): Promise<ChatResponseDto>;

  /**
   * Perform a streaming chat completion.
   * Yields response chunks as they arrive from the provider.
   *
   * @param request - Chat request with messages and configuration
   * @yields Chat response chunks
   * @throws {Error} If provider is not initialized or request fails
   */
  chatStream(request: ChatRequestDto): AsyncGenerator<ChatResponseDto>;

  /**
   * Generate embeddings for the given input texts.
   *
   * @param request - Embedding request with model and input texts
   * @returns Embeddings response with vector arrays
   * @throws {Error} If provider is not initialized or request fails
   */
  embed(request: EmbedRequestDto): Promise<EmbedResponseDto>;

  /**
   * Get the current provider configuration.
   * Should return a copy to prevent external modification.
   *
   * @returns Provider configuration object
   */
  getConfig(): LlmProviderConfig;
}
