import { Conversation } from './classes.conversation.js';
import * as plugins from './plugins.js';
import { AnthropicProvider } from './provider.anthropic.js';
import { ElevenLabsProvider } from './provider.elevenlabs.js';
import { MistralProvider } from './provider.mistral.js';
import { OllamaProvider } from './provider.ollama.js';
import { OpenAiProvider } from './provider.openai.js';
import { PerplexityProvider } from './provider.perplexity.js';
import { ExoProvider } from './provider.exo.js';
import { GroqProvider } from './provider.groq.js';
import { XAIProvider } from './provider.xai.js';


export interface ISmartAiOptions {
  openaiToken?: string;
  anthropicToken?: string;
  perplexityToken?: string;
  groqToken?: string;
  mistralToken?: string;
  xaiToken?: string;
  elevenlabsToken?: string;
  exo?: {
    baseUrl?: string;
    apiKey?: string;
  };
  mistral?: {
    chatModel?: string;
    ocrModel?: string;
    tableFormat?: 'markdown' | 'html';
  };
  ollama?: {
    baseUrl?: string;
    model?: string;
    visionModel?: string;
    defaultOptions?: {
      num_ctx?: number;
      temperature?: number;
      top_k?: number;
      top_p?: number;
      repeat_penalty?: number;
      num_predict?: number;
      stop?: string[];
      seed?: number;
    };
    defaultTimeout?: number;
  };
  elevenlabs?: {
    defaultVoiceId?: string;
    defaultModelId?: string;
  };
}

export type TProvider = 'openai' | 'anthropic' | 'perplexity' | 'ollama' | 'exo' | 'groq' | 'mistral' | 'xai' | 'elevenlabs';

export class SmartAi {
  public options: ISmartAiOptions;

  public openaiProvider: OpenAiProvider;
  public anthropicProvider: AnthropicProvider;
  public perplexityProvider: PerplexityProvider;
  public ollamaProvider: OllamaProvider;
  public exoProvider: ExoProvider;
  public groqProvider: GroqProvider;
  public mistralProvider: MistralProvider;
  public xaiProvider: XAIProvider;
  public elevenlabsProvider: ElevenLabsProvider;

  constructor(optionsArg: ISmartAiOptions) {
    this.options = optionsArg;
  }

  public async start() {
    if (this.options.openaiToken) {
      this.openaiProvider = new OpenAiProvider({
        openaiToken: this.options.openaiToken,
      });
      await this.openaiProvider.start();
    }
    if (this.options.anthropicToken) {
      this.anthropicProvider = new AnthropicProvider({
        anthropicToken: this.options.anthropicToken,
      });
      await this.anthropicProvider.start();
    }
    if (this.options.perplexityToken) {
      this.perplexityProvider = new PerplexityProvider({
        perplexityToken: this.options.perplexityToken,
      });
      await this.perplexityProvider.start();
    }
    if (this.options.groqToken) {
      this.groqProvider = new GroqProvider({
        groqToken: this.options.groqToken,
      });
      await this.groqProvider.start();
    }
    if (this.options.mistralToken) {
      this.mistralProvider = new MistralProvider({
        mistralToken: this.options.mistralToken,
        chatModel: this.options.mistral?.chatModel,
        ocrModel: this.options.mistral?.ocrModel,
        tableFormat: this.options.mistral?.tableFormat,
      });
      await this.mistralProvider.start();
    }
    if (this.options.xaiToken) {
      this.xaiProvider = new XAIProvider({
        xaiToken: this.options.xaiToken,
      });
      await this.xaiProvider.start();
    }
    if (this.options.elevenlabsToken) {
      this.elevenlabsProvider = new ElevenLabsProvider({
        elevenlabsToken: this.options.elevenlabsToken,
        defaultVoiceId: this.options.elevenlabs?.defaultVoiceId,
        defaultModelId: this.options.elevenlabs?.defaultModelId,
      });
      await this.elevenlabsProvider.start();
    }
    if (this.options.ollama) {
      this.ollamaProvider = new OllamaProvider({
        baseUrl: this.options.ollama.baseUrl,
        model: this.options.ollama.model,
        visionModel: this.options.ollama.visionModel,
        defaultOptions: this.options.ollama.defaultOptions,
        defaultTimeout: this.options.ollama.defaultTimeout,
      });
      await this.ollamaProvider.start();
    }
    if (this.options.exo) {
      this.exoProvider = new ExoProvider({
        exoBaseUrl: this.options.exo.baseUrl,
        apiKey: this.options.exo.apiKey,
      });
      await this.exoProvider.start();
    }
  }

  public async stop() {
    if (this.openaiProvider) {
      await this.openaiProvider.stop();
    }
    if (this.anthropicProvider) {
      await this.anthropicProvider.stop();
    }
    if (this.perplexityProvider) {
      await this.perplexityProvider.stop();
    }
    if (this.groqProvider) {
      await this.groqProvider.stop();
    }
    if (this.mistralProvider) {
      await this.mistralProvider.stop();
    }
    if (this.xaiProvider) {
      await this.xaiProvider.stop();
    }
    if (this.elevenlabsProvider) {
      await this.elevenlabsProvider.stop();
    }
    if (this.ollamaProvider) {
      await this.ollamaProvider.stop();
    }
    if (this.exoProvider) {
      await this.exoProvider.stop();
    }
  }
  
  /**
   * create a new conversation
   */
  createConversation(provider: TProvider) {
    switch (provider) {
      case 'exo':
        return Conversation.createWithExo(this);
      case 'openai':
        return Conversation.createWithOpenAi(this);
      case 'anthropic':
        return Conversation.createWithAnthropic(this);
      case 'perplexity':
        return Conversation.createWithPerplexity(this);
      case 'ollama':
        return Conversation.createWithOllama(this);
      case 'groq':
        return Conversation.createWithGroq(this);
      case 'mistral':
        return Conversation.createWithMistral(this);
      case 'xai':
        return Conversation.createWithXai(this);
      case 'elevenlabs':
        return Conversation.createWithElevenlabs(this);
      default:
        throw new Error('Provider not available');
    }
  }
}