import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import type { FastifyBaseLogger } from 'fastify';
import { LLMProviderFactory, type ModelConfig, LLMProvider } from './provider.js';
import type { UserLicense } from '../types/user.js';

/**
 * Model routing strategies
 */
export enum RoutingStrategy {
  /** Use user's preferred model from license */
  USER_PREFERENCE = 'user_preference',
  /** Route based on query complexity */
  COMPLEXITY = 'complexity',
  /** Route based on license tier */
  LICENSE_TIER = 'license_tier',
  /** Use cheapest available model */
  COST_OPTIMIZED = 'cost_optimized',
}

/**
 * Model router
 * Intelligently selects which model to use based on various factors
 */
export class ModelRouter {
  private factory: LLMProviderFactory;
  private logger: FastifyBaseLogger;
  private defaultModel: ModelConfig;

  constructor(factory: LLMProviderFactory, logger: FastifyBaseLogger) {
    this.factory = factory;
    this.logger = logger;
    this.defaultModel = factory.getDefaultModel();
  }

  /**
   * Route to appropriate model based on context
   */
  async route(
    message: string,
    license: UserLicense,
    strategy: RoutingStrategy = RoutingStrategy.USER_PREFERENCE
  ): Promise<BaseChatModel> {
    let modelConfig: ModelConfig;

    switch (strategy) {
      case RoutingStrategy.USER_PREFERENCE:
        modelConfig = this.routeByUserPreference(license);
        break;

      case RoutingStrategy.COMPLEXITY:
        modelConfig = this.routeByComplexity(message, license);
        break;

      case RoutingStrategy.LICENSE_TIER:
        modelConfig = this.routeByLicenseTier(license);
        break;

      case RoutingStrategy.COST_OPTIMIZED:
        modelConfig = this.routeByCost(license);
        break;

      default:
        modelConfig = this.defaultModel;
    }

    this.logger.info(
      {
        userId: license.userId,
        strategy,
        provider: modelConfig.provider,
        model: modelConfig.model,
      },
      'Routing to model'
    );

    return this.factory.createModel(modelConfig);
  }

  /**
   * Route based on user's preferred model (if set in license)
   */
  private routeByUserPreference(license: UserLicense): ModelConfig {
    // Check if user has custom model preference
    const preferredModel = (license as any).preferredModel as ModelConfig | undefined;

    if (preferredModel && this.isModelAllowed(preferredModel, license)) {
      return preferredModel;
    }

    // Fall back to license tier default
    return this.routeByLicenseTier(license);
  }

  /**
   * Route based on query complexity
   */
  private routeByComplexity(message: string, license: UserLicense): ModelConfig {
    const isComplex = this.isComplexQuery(message);

    if (license.licenseType === 'enterprise') {
      // Enterprise users get best models for complex queries
      return isComplex
        ? { provider: LLMProvider.ANTHROPIC, model: 'claude-3-opus-20240229' }
        : { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' };
    }

    if (license.licenseType === 'pro') {
      // Pro users get good models
      return isComplex
        ? { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' }
        : { provider: LLMProvider.OPENAI, model: 'gpt-4o-mini' };
    }

    // Free users get efficient models
    return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };
  }

  /**
   * Route based on license tier
   */
  private routeByLicenseTier(license: UserLicense): ModelConfig {
    switch (license.licenseType) {
      case 'enterprise':
        return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' };

      case 'pro':
        return { provider: LLMProvider.OPENAI, model: 'gpt-4o' };

      case 'free':
        return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };

      default:
        return this.defaultModel;
    }
  }

  /**
   * Route to cheapest available model
   */
  private routeByCost(license: UserLicense): ModelConfig {
    // Free tier: use cheapest
    if (license.licenseType === 'free') {
      return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };
    }

    // Paid tiers: use GPT-4o-mini for cost efficiency
    return { provider: LLMProvider.OPENAI, model: 'gpt-4o-mini' };
  }

  /**
   * Check if model is allowed for user's license
   */
  private isModelAllowed(model: ModelConfig, license: UserLicense): boolean {
    // Free tier: only cheap models
    if (license.licenseType === 'free') {
      const allowedModels = ['gemini-2.0-flash-exp', 'gpt-4o-mini', 'claude-3-5-haiku-20241022'];
      return allowedModels.includes(model.model);
    }

    // Pro: all except Opus
    if (license.licenseType === 'pro') {
      const blockedModels = ['claude-3-opus-20240229'];
      return !blockedModels.includes(model.model);
    }

    // Enterprise: all models allowed
    return true;
  }

  /**
   * Determine if query is complex
   */
  private isComplexQuery(message: string): boolean {
    const complexityIndicators = [
      // Multi-step analysis
      'backtest',
      'analyze',
      'compare',
      'optimize',

      // Code generation
      'write',
      'create',
      'implement',
      'build',

      // Deep reasoning
      'explain why',
      'what if',
      'how would',

      // Long messages (> 200 chars likely complex)
      message.length > 200,
    ];

    const messageLower = message.toLowerCase();

    return complexityIndicators.some((indicator) =>
      typeof indicator === 'string' ? messageLower.includes(indicator) : indicator
    );
  }
}
