/**
 * ModelConfigLoader - Loads model configuration from YAML files
 *
 * Implements DD §12.2.
 * Loads global ~/.air/models.yaml + project config.
 *
 * @module packages/llm/src/ModelConfigLoader
 */

import { readFileSync, existsSync } from 'fs'
import { resolve, join } from 'path'
import { homedir } from 'os'

export interface ModelConfig {
  provider: string
  model: string
  /** @deprecated Use auth_ref instead for security */
  api_key?: string
  /** Reference to external credential store (e.g., env:ANTHROPIC_API_KEY) */
  auth_ref?: string
  base_url?: string
  max_tokens?: number
  temperature?: number
  top_p?: number
}

export interface ModelConfigSet {
  global?: Record<string, ModelConfig>
  project?: Record<string, ModelConfig>
}

export interface ConfigLoadResult {
  ok: boolean
  configs?: ModelConfigSet
  error?: string
}

const DEFAULT_CONFIG_PATH = join(homedir(), '.air', 'models.yaml')

export class ModelConfigLoader {
  private global_config_path: string
  private project_config_path?: string

  constructor(global_path?: string, project_path?: string) {
    this.global_config_path = global_path || DEFAULT_CONFIG_PATH
    this.project_config_path = project_path
  }

  /**
   * Load all model configurations.
   */
  load(): ConfigLoadResult {
    const configs: ModelConfigSet = {}

    // Load global config
    if (existsSync(this.global_config_path)) {
      try {
        const content = readFileSync(this.global_config_path, 'utf-8')
        configs.global = this.parse_yaml(content)
      } catch (error) {
        return { ok: false, error: `Failed to load global config: ${error instanceof Error ? error.message : String(error)}` }
      }
    }

    // Load project config if specified
    if (this.project_config_path && existsSync(this.project_config_path)) {
      try {
        const content = readFileSync(this.project_config_path, 'utf-8')
        configs.project = this.parse_yaml(content)
      } catch (error) {
        return { ok: false, error: `Failed to load project config: ${error instanceof Error ? error.message : String(error)}` }
      }
    }

    return { ok: true, configs }
  }

  /**
   * Get config for a specific model by name.
   */
  get_model(name: string): ModelConfig | undefined {
    const result = this.load()
    if (!result.ok || !result.configs) return undefined

    // Project config takes precedence over global
    if (result.configs.project?.[name]) {
      return result.configs.project[name]
    }

    return result.configs.global?.[name]
  }

  /**
   * Validate required fields in a model config.
   */
  validate(config: ModelConfig): { valid: boolean; error?: string } {
    if (!config.provider) {
      return { valid: false, error: 'provider is required' }
    }
    if (!config.model) {
      return { valid: false, error: 'model is required' }
    }

    // Provider-specific validation - require auth_ref for security
    if (config.provider === 'anthropic') {
      if (config.api_key) {
        return { valid: false, error: 'Direct api_key is deprecated; use auth_ref instead (e.g., env:ANTHROPIC_API_KEY)' }
      }
      if (!config.auth_ref) {
        const env_key = this.resolve_auth_ref(config.auth_ref)
        if (!env_key || !process.env[env_key]) {
          return { valid: false, error: 'anthropic requires auth_ref (e.g., env:ANTHROPIC_API_KEY)' }
        }
      }
    }

    if (config.provider === 'openai' || config.provider === 'openai-compatible') {
      if (!config.api_key && !config.auth_ref && !process.env.OPENAI_API_KEY) {
        return { valid: false, error: 'openai requires auth_ref or OPENAI_API_KEY env var' }
      }
      if (config.api_key) {
        return { valid: false, error: 'Direct api_key is deprecated; use auth_ref instead' }
      }
    }

    return { valid: true }
  }

  /**
   * Resolve auth_ref to environment variable name.
   */
  resolve_auth_ref(auth_ref?: string): string | null {
    if (!auth_ref) return null
    if (auth_ref.startsWith('env:')) {
      return auth_ref.slice(4)
    }
    return null
  }

  /**
   * Simple YAML parser for model configs.
   * In production, use a proper YAML library.
   */
  private parse_yaml(content: string): Record<string, ModelConfig> {
    const result: Record<string, ModelConfig> = {}
    const lines = content.split('\n')
    let current_key = ''
    let current_config: Partial<ModelConfig> = {}

    for (const line of lines) {
      const trimmed = line.trim()

      // Skip comments and empty lines
      if (!trimmed || trimmed.startsWith('#')) continue

      // Check for top-level key (model name)
      if (trimmed.endsWith(':') && !trimmed.includes(' ')) {
        // Save previous config
        if (current_key && current_config.provider) {
          result[current_key] = current_config as ModelConfig
        }
        current_key = trimmed.slice(0, -1)
        current_config = {}
        continue
      }

      // Parse key: value pairs
      const colon_idx = trimmed.indexOf(':')
      if (colon_idx > 0) {
        const key = trimmed.slice(0, colon_idx).trim()
        const value = trimmed.slice(colon_idx + 1).trim()

        // Remove quotes from value
        const clean_value = value.replace(/^["']|["']$/g, '')

        switch (key) {
          case 'provider':
            current_config.provider = clean_value
            break
          case 'model':
            current_config.model = clean_value
            break
          case 'api_key':
            current_config.api_key = clean_value
            break
          case 'auth_ref':
            current_config.auth_ref = clean_value
            break
          case 'base_url':
            current_config.base_url = clean_value
            break
          case 'max_tokens':
            current_config.max_tokens = parseInt(clean_value, 10)
            break
          case 'temperature':
            current_config.temperature = parseFloat(clean_value)
            break
          case 'top_p':
            current_config.top_p = parseFloat(clean_value)
            break
        }
      }
    }

    // Save last config
    if (current_key && current_config.provider) {
      result[current_key] = current_config as ModelConfig
    }

    return result
  }
}

export function createModelConfigLoader(global_path?: string, project_path?: string): ModelConfigLoader {
  return new ModelConfigLoader(global_path, project_path)
}