import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { ChatOpenAI } from '@langchain/openai';
import type { FastifyBaseLogger } from 'fastify';
import { type ModelMiddleware, NoopMiddleware, AnthropicCachingMiddleware } from './middleware.js';

export type { ModelMiddleware };
export { NoopMiddleware, AnthropicCachingMiddleware };

/**
 * Supported LLM providers
 */
export enum LLMProvider {
  DEEP_INFRA = 'deepinfra',
}

/**
 * Model configuration
 */
export interface ModelConfig {
  provider: LLMProvider;
  model: string;
  temperature?: number;
  maxTokens?: number;
}

/**
 * License tier model configuration
 */
export interface LicenseTierModels {
  default: string;
  cost_optimized: string;
  complex: string;
  allowed_models?: string[];
  blocked_models?: string[];
}

/**
 * License models configuration
 */
export interface LicenseModelsConfig {
  free: LicenseTierModels;
  pro: LicenseTierModels;
  enterprise: LicenseTierModels;
}

/**
 * Provider configuration with API keys
 */
export interface ProviderConfig {
  deepinfraApiKey?: string;
  defaultModel?: ModelConfig;
  licenseModels?: LicenseModelsConfig;
}

const DEEP_INFRA_BASE_URL = 'https://api.deepinfra.com/v1/openai';

/**
 * LLM Provider factory
 * Creates model instances with unified interface across providers
 */
export class LLMProviderFactory {
  private config: ProviderConfig;
  private logger: FastifyBaseLogger;

  constructor(config: ProviderConfig, logger: FastifyBaseLogger) {
    this.config = config;
    this.logger = logger;
  }

  /**
   * Create a chat model instance
   */
  createModel(modelConfig: ModelConfig): { model: BaseChatModel; middleware: ModelMiddleware } {
    this.logger.debug(
      { provider: modelConfig.provider, model: modelConfig.model },
      'Creating LLM model'
    );

    switch (modelConfig.provider) {
      case LLMProvider.DEEP_INFRA:
        return this.createDeepInfraModel(modelConfig);

      default:
        throw new Error(`Unsupported provider: ${modelConfig.provider}`);
    }
  }

  /**
   * Create Deep Infra model via OpenAI-compatible API
   */
  private createDeepInfraModel(config: ModelConfig): { model: ChatOpenAI; middleware: NoopMiddleware } {
    if (!this.config.deepinfraApiKey) {
      throw new Error('Deep Infra API key not configured');
    }

    const model = new ChatOpenAI({
      model: config.model,
      temperature: config.temperature ?? 0.7,
      maxTokens: config.maxTokens ?? 4096,
      apiKey: this.config.deepinfraApiKey,
      configuration: {
        baseURL: DEEP_INFRA_BASE_URL,
      },
    });

    return { model, middleware: new NoopMiddleware() };
  }

  /**
   * Get default model based on environment
   */
  getDefaultModel(): ModelConfig {
    if (this.config.defaultModel) {
      return this.config.defaultModel;
    }

    if (!this.config.deepinfraApiKey) {
      throw new Error('Deep Infra API key not configured');
    }

    return {
      provider: LLMProvider.DEEP_INFRA,
      model: 'zai-org/GLM-5',
    };
  }

  /**
   * Get license models configuration
   */
  getLicenseModelsConfig(): LicenseModelsConfig | undefined {
    return this.config.licenseModels;
  }
}

/**
 * Predefined model configurations
 */
export const MODELS = {
  GLM_5: {
    provider: LLMProvider.DEEP_INFRA,
    model: 'zai-org/GLM-5',
  },
  QWEN_235B: {
    provider: LLMProvider.DEEP_INFRA,
    model: 'Qwen/Qwen3-235B-A22B-Instruct-2507',
  },
} as const satisfies Record<string, ModelConfig>;
