import { ChatMessage, ChatOptions, ProviderResponse } from './chat';
import { Tool, GenericToolSchema, StandardizedToolCall } from './tool';

export class AIProviderError extends Error {
  code: string;
  provider?: string;
  details?: any;
  retryable?: boolean;

  constructor(message: string, code: string, provider?: string, details?: any, retryable?: boolean) {
    super(message);
    this.name = 'AIProviderError';
    this.code = code;
    if (provider) {
      this.provider = provider;
    }
    if (details) {
      this.details = details;
    }
    if (retryable !== undefined) {
      this.retryable = retryable;
    }
  }
}

export interface ProviderCapabilities {
  maxTokens: number;
  supportsFunctionCalling: boolean;
  supportsStreaming: boolean;
  supportedModels: string[];
  maxSimultaneousCalls: number;
  supportsSemanticCaching: boolean;
}

export interface IAIProvider {
  chat(messages: ChatMessage[], options: ChatOptions, tools?: Tool[]): Promise<ProviderResponse>;
  streamChat(messages: ChatMessage[], options: ChatOptions, tools?: Tool[]): AsyncIterableIterator<ProviderResponse>;
  getCapabilities(): ProviderCapabilities;
  use(middleware: AIProviderMiddleware): void;
  registerPlugin(plugin: AIProviderPlugin): void;
  convertToolSchema(schema: GenericToolSchema): any;
  convertToolCall(call: any): StandardizedToolCall;
}

export interface AIProviderMiddleware {
  preProcess(messages: ChatMessage[]): Promise<ChatMessage[]>;
  postProcess(response: ProviderResponse): Promise<ProviderResponse>;
  processToolCalls?(toolCalls: StandardizedToolCall[]): Promise<StandardizedToolCall[]>;
}

export interface AIProviderPlugin {
  initialize(provider: IAIProvider): void;
  onBeforeChat?(messages: ChatMessage[], options: ChatOptions): Promise<void>;
  onAfterChat?(response: ProviderResponse): Promise<void>;
  onError?(error: AIProviderError): Promise<void>;
  onStreamStart?(): Promise<void>;
  onStreamChunk?(chunk: any): Promise<void>;
  onStreamEnd?(): Promise<void>;
}

export interface EmbeddingProvider {
  embed(text: string): Promise<number[]>;
  embedBatch(texts: string[]): Promise<number[][]>;
}

export interface AIClientConfig {
  apiKey: string;
  [key: string]: any;
}

export interface AIProviderConfig extends AIClientConfig {
  type?: string;
}

export interface OpenAIProviderConfig extends AIProviderConfig {
  model: string;
}

export interface AnthropicProviderConfig extends AIProviderConfig {
  model: string;
}

export interface AzureProviderConfig extends AIProviderConfig {
  endpoint: string;
  deploymentId: string;
  subscriptionId: string;
  deployment: string;
}

export interface VertexProviderConfig extends AIProviderConfig {
  model: string;
  projectId: string;
  location: string;
}

export interface OpenRouterProviderConfig extends AIProviderConfig {
  model: string;
  httpReferer?: string;
  xTitle?: string;
}

export interface IAIProviderFactory {
  createProvider(config: AIProviderConfig): IAIProvider;
}