import {
  AIProvider,
  ProviderType,
  ExecutionMode,
  ProviderConfig,
  ProviderError,
} from './provider.js';
import { AnthropicProvider } from './anthropic.js';
import { OpenAIProvider } from './openai.js';
import { GeminiProvider } from './gemini.js';
import { CodingAgentProvider } from './coding-agent.js';

export {
  ProviderError,
  ProviderUnavailableError,
  ProviderRateLimitError,
  type AIProvider,
  type ProviderOptions,
  type ProviderResult,
  type StreamChunk,
  type ToolDefinition,
  type ToolCall,
  type ProviderType,
  type ExecutionMode,
  type ProviderConfig,
};

export { AnthropicProvider } from './anthropic.js';
export { OpenAIProvider } from './openai.js';
export { GeminiProvider } from './gemini.js';
export { CodingAgentProvider } from './coding-agent.js';

const PROVIDERS: Record<ProviderType, new (config: ProviderConfig) => AIProvider> = {
  claude: AnthropicProvider,
  openai: OpenAIProvider,
  gemini: GeminiProvider,
};

export function createProvider(
  type: ProviderType,
  config: ProviderConfig = {}
): AIProvider {
  const ProviderClass = PROVIDERS[type];
  if (!ProviderClass) {
    throw new ProviderError(`Unknown provider type: ${type}`, 'factory');
  }
  return new ProviderClass(config);
}

export function createProviderFromEnv(): AIProvider {
  const providerType = (process.env.AI_PROVIDER || 'claude') as ProviderType;
  
  if (!['claude', 'openai', 'gemini'].includes(providerType)) {
    throw new ProviderError(
      `Invalid AI_PROVIDER: ${providerType}. Must be claude, openai, or gemini`,
      'factory'
    );
  }

  const config: ProviderConfig = {
    model: process.env.CLAUDE_MODEL || process.env.OPENAI_MODEL || process.env.GEMINI_MODEL,
  };

  switch (providerType) {
    case 'claude':
      config.apiKey = process.env.ANTHROPIC_API_KEY;
      break;
    case 'openai':
      config.apiKey = process.env.OPENAI_API_KEY;
      config.organizationId = process.env.OPENAI_ORG_ID;
      break;
    case 'gemini':
      config.apiKey = process.env.GOOGLE_API_KEY;
      break;
  }

  return createProvider(providerType, config);
}

export function createExecutionProvider(
  mode: ExecutionMode = 'container',
  providerType?: ProviderType
): AIProvider {
  const actualMode = mode || (process.env.EXECUTION_MODE as ExecutionMode) || 'container';
  const actualType = providerType || (process.env.AI_PROVIDER as ProviderType) || 'claude';

  switch (actualMode) {
    case 'tui':
      return new CodingAgentProvider({
        model: process.env.CLAUDE_MODEL,
      });
    
    case 'direct':
      return createProviderFromEnv();
    
    case 'container':
    default:
      // Container mode uses the provider config passed to the container
      return createProvider(actualType, {
        apiKey: process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GOOGLE_API_KEY,
        model: process.env.CLAUDE_MODEL || process.env.OPENAI_MODEL || process.env.GEMINI_MODEL,
      });
  }
}

export function getAvailableProviders(): ProviderType[] {
  const available: ProviderType[] = [];

  if (process.env.ANTHROPIC_API_KEY || process.env.AGENT_CODE_OAUTH_TOKEN) {
    available.push('claude');
  }

  if (process.env.OPENAI_API_KEY) {
    available.push('openai');
  }

  if (process.env.GOOGLE_API_KEY) {
    available.push('gemini');
  }

  return available;
}

export function getDefaultProvider(): ProviderType {
  const available = getAvailableProviders();
  
  if (available.includes('claude')) {
    return 'claude';
  }
  
  if (available.includes('openai')) {
    return 'openai';
  }
  
  if (available.includes('gemini')) {
    return 'gemini';
  }

  throw new ProviderError(
    'No AI provider configured. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY',
    'factory'
  );
}
