/**
 * Vendor-Aware Model Registry。
 *
 * 职责：
 * 1. 按厂商动态发现模型列表。
 * 2. 维护模型能力元数据（thinking/effort/vision/fast 等）。
 * 3. 根据 provider 凭证状态过滤可用模型。
 * 4. 提供默认模型解析与模型 → 凭证解析。
 */

import { apiProviderRepo } from '@/lib/database/repositories/api-provider.repo'
import { providerModelRepo } from '@/lib/database/repositories/provider-model.repo'
import { isClaudeCliAuthenticated } from '@/lib/claude-cli-auth'
import { BUILTIN_API_PROVIDERS } from '@/lib/api-provider-catalog'
import { ApiProviderStatus } from '@/lib/database/shared/enums'
import type { ProviderType } from '@/lib/types'
import {
  AnthropicAdapter,
  MoonshotAdapter,
  ZhipuAdapter,
  QwenAdapter,
  MiniMaxAdapter,
  DeepSeekAdapter,
  CustomAdapter,
} from './adapters'
import type {
  ConnectionTestResult,
  ModelRecord,
  ProviderAdapter,
  ProviderCredential,
  RegistryOptions,
  ResolvedModel,
} from './types'

const builtinAdapters: Record<string, ProviderAdapter> = {
  anthropic: new AnthropicAdapter(),
  moonshot: new MoonshotAdapter(),
  zhipu: new ZhipuAdapter(),
  qwen: new QwenAdapter(),
  minimax: new MiniMaxAdapter(),
  deepseek: new DeepSeekAdapter(),
}

const builtinNameMap: Record<string, string> = Object.fromEntries(
  BUILTIN_API_PROVIDERS.map((p) => [p.provider, p.name]),
)

function getAdapter(providerId: string): ProviderAdapter {
  if (providerId.startsWith('custom-')) return new CustomAdapter()
  return builtinAdapters[providerId] ?? new CustomAdapter()
}

function displayNameFor(providerId: string, fallback?: string): string {
  if (providerId.startsWith('custom-')) return fallback || providerId
  return builtinNameMap[providerId] || providerId
}

interface ProviderRow {
  id: string
  name: string
  provider: string
  apiKey: string
  baseUrl: string
  modelName: string
  isActive: number
  status: string
  statusError: string
  modelsFetchedAt?: string
  modelsFetchError?: string
  createdAt: string
  updatedAt: string
}

function isProviderActive(row: ProviderRow): boolean {
  if (row.status === ApiProviderStatus.CONNECTED || row.status === ApiProviderStatus.CLI_AUTHENTICATED) return true
  if (row.provider === 'anthropic' && !row.apiKey && isClaudeCliAuthenticated()) return true
  return false
}

function nowIso(): string {
  return new Date().toISOString()
}

function getProviderRows(userId: string): ProviderRow[] {
  const saved = apiProviderRepo.listByUser(userId)
  const savedMap = new Map(saved.map((r) => [r.provider === 'custom' ? r.id : r.provider, r]))

  const rows: ProviderRow[] = BUILTIN_API_PROVIDERS.map((entry) => {
    const saved = savedMap.get(entry.provider)
    if (saved) return saved as ProviderRow
    const row: ProviderRow = {
      id: entry.provider,
      name: entry.name,
      provider: entry.provider,
      apiKey: '',
      baseUrl: '',
      modelName: '',
      isActive: 0,
      status: ApiProviderStatus.NOT_CONFIGURED,
      statusError: '',
      modelsFetchedAt: '',
      modelsFetchError: '',
      createdAt: '',
      updatedAt: '',
    }
    return row
  })

  const customRows = saved.filter((r) => r.provider === 'custom')
  return [...rows, ...customRows]
}

/**
 * 用 seed 润色 dynamic 的展示元数据，不改变可用性集合。
 * dynamic 决定「有哪些模型」；seed 仅补充 label / capabilities / aliases。
 */
function enrichFromSeeds(dynamic: ModelRecord[], seeds: ModelRecord[]): ModelRecord[] {
  if (seeds.length === 0) return dynamic
  const seedMap = new Map(seeds.map((s) => [s.id, s]))
  return dynamic.map((d) => {
    const seed = seedMap.get(d.id)
    if (!seed) return d
    const seedLabelBetter = seed.label && seed.label !== seed.id
    const dynLabelIsRaw = !d.label || d.label === d.id
    return {
      ...d,
      label: seedLabelBetter && dynLabelIsRaw ? seed.label : d.label,
      capabilities: { ...seed.capabilities, ...d.capabilities },
      aliases: seed.aliases?.length ? seed.aliases : d.aliases,
      source: d.source || 'dynamic',
    }
  })
}

async function getSeedModels(
  providerId: string,
  baseUrl?: string,
  modelName?: string,
): Promise<ModelRecord[]> {
  const adapter = getAdapter(providerId)
  return adapter.listModels({
    providerId,
    apiKey: '',
    baseUrl,
    modelName,
    authType: adapter.authType,
  })
}

function storedToRecord(row: ReturnType<typeof providerModelRepo.listByUser>[number]): ModelRecord {
  return {
    id: row.modelId,
    label: row.label,
    providerId: row.providerId,
    providerName: displayNameFor(row.providerId, row.providerId),
    capabilities: row.capabilities as ModelRecord['capabilities'],
    aliases: row.aliases,
    source: row.source,
    status: row.status,
  }
}

export const modelRegistry = {
  /**
   * 返回当前用户可用的模型列表。
   * - 未配置/未认证的 provider 的模型不会出现在结果中（除非 includeInactive=true）。
   * - 已刷新过的 provider 使用数据库中的动态记录；未刷新过的使用 adapter seed 列表。
   */
  async getAvailableModels(userId: string, options: RegistryOptions = {}): Promise<ModelRecord[]> {
    const rows = getProviderRows(userId)
    const results: ModelRecord[] = []

    for (const row of rows) {
      const providerId = row.provider === 'custom' ? row.id : row.provider
      const active = isProviderActive(row)
      if (!active && !options.includeInactive) continue

      const stored = providerModelRepo.listByProvider(providerId, userId)
      let records: ModelRecord[]
      if (stored.length > 0) {
        records = stored.map(storedToRecord)
      } else {
        try {
          records = await getSeedModels(
            providerId,
            row.baseUrl || undefined,
            row.modelName || undefined,
          )
        } catch {
          // seed 路径不应失败；兜底为空，避免单个 provider 拖垮整表
          records = []
        }
      }

      for (const r of records) {
        results.push({
          ...r,
          providerId,
          providerName: displayNameFor(providerId, row.name),
          status: active ? 'available' : 'unavailable',
        })
      }
    }

    return results
  },

  /**
   * 强制刷新某个 provider 的模型列表并持久化。
   * - 成功：全量覆盖 DB（厂商返回什么就是什么），seed 仅用于 enrich 元数据。
   * - 失败：不碰 provider_models，只写 models_fetch_error，并 rethrow。
   */
  async refreshProviderModels(providerId: string, userId: string): Promise<ModelRecord[]> {
    const adapter = getAdapter(providerId)
    const row = apiProviderRepo.findRawByIdAndUser(providerId, userId)
    const apiKey = row?.apiKey || ''
    const credential: ProviderCredential = {
      providerId,
      apiKey,
      baseUrl: row?.baseUrl || undefined,
      modelName: row?.modelName || undefined,
      authType: adapter.authType,
    }

    // 无 API Key 时刷新无意义：adapter 只会返回 seed，不发网络请求。
    // 直接抛错，由调用方决定如何展示（前端按钮已隐藏；refreshAll 已跳过）。
    if (!apiKey) {
      throw new Error('请先配置 API Key 后再刷新模型')
    }

    try {
      const dynamic = await adapter.listModels(credential)
      // 空列表视为失败，避免一次异常响应清空已有可用模型
      if (dynamic.length === 0) {
        throw new Error('厂商未返回任何模型')
      }

      const seeds = await getSeedModels(
        providerId,
        credential.baseUrl,
        credential.modelName,
      )
      const enriched = enrichFromSeeds(dynamic, seeds)
      providerModelRepo.replaceProviderModels(providerId, userId, enriched)
      apiProviderRepo.updateFetchMeta(providerId, userId, nowIso(), '')

      return enriched.map((r) => ({
        ...r,
        providerId,
        providerName: displayNameFor(providerId, row?.name),
        status: 'available' as const,
      }))
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'Model discovery failed'
      apiProviderRepo.updateFetchMeta(providerId, userId, nowIso(), errorMsg)
      throw err instanceof Error ? err : new Error(errorMsg)
    }
  },
  async refreshAll(userId: string): Promise<void> {
    const rows = getProviderRows(userId)
    for (const row of rows) {
      const providerId = row.provider === 'custom' ? row.id : row.provider
      // 跳过未配置 API Key 的 provider，避免无意义的 seed 写库。
      if (!row.apiKey) continue
      try {
        await this.refreshProviderModels(providerId, userId)
      } catch (err) {
        // 单个 provider 失败已写入 models_fetch_error，继续刷新其余
        console.warn(
          `[modelRegistry.refreshAll] ${providerId}:`,
          err instanceof Error ? err.message : err,
        )
      }
    }
  },

  /**
   * 测试 provider 连接：委托对应 adapter.testConnection。
   * 国产厂商走 Anthropic-compatible 最小 messages 探测（与真实对话路径一致）。
   */
  async testProviderConnection(providerId: string, userId: string): Promise<ConnectionTestResult> {
    const adapter = getAdapter(providerId)
    const row = apiProviderRepo.findRawByIdAndUser(providerId, userId)
    if (!row?.apiKey) {
      return { ok: false, error: 'No API key configured' }
    }
    const credential: ProviderCredential = {
      providerId,
      apiKey: row.apiKey,
      baseUrl: row.baseUrl || undefined,
      modelName: row.modelName || undefined,
      authType: adapter.authType,
    }
    return adapter.testConnection(credential)
  },

  /**
   * 解析单个模型：返回模型记录 + 实际请求需要的凭证信息。
   */
  async resolveModel(modelId: string, userId: string): Promise<ResolvedModel | undefined> {
    // 1. 从已发现记录或 seed 中找模型元数据
    const stored = providerModelRepo.listByUser(userId).find((m) => m.modelId === modelId)
    let record: ModelRecord | undefined
    if (stored) {
      record = storedToRecord(stored)
    }

    if (!record) {
      for (const providerId of Object.keys(builtinAdapters)) {
        const seeds = await getSeedModels(providerId)
        const found = seeds.find((s) => s.id === modelId)
        if (found) {
          record = { ...found, providerId }
          break
        }
      }
    }

    if (!record) return undefined

    // 2. 解析凭证
    const providerId = record.providerId
    let apiKey = ''
    let baseUrl: string | undefined
    let authType: 'api_key' | 'auth_token' = 'auth_token'
    let isCliAuth = false

    if (providerId.startsWith('custom-')) {
      const row = apiProviderRepo.findRawByIdAndUser(providerId, userId)
      if (!row) return undefined
      apiKey = row.apiKey
      baseUrl = row.baseUrl || undefined
      authType = 'auth_token'
    } else {
      const adapter = getAdapter(providerId)
      authType = adapter.authType
      const row = apiProviderRepo.findCredentialByProvider(providerId, userId)
      apiKey = row?.apiKey || ''
      baseUrl = row?.baseUrl || adapter.defaultBaseUrl
      if (providerId === 'anthropic' && !apiKey && isClaudeCliAuthenticated()) {
        isCliAuth = true
      }
    }

    return {
      record,
      apiKey,
      baseUrl,
      authType,
      isCliAuth,
    }
  },

  /**
   * 解析默认模型。
   * - 优先使用用户设置的 fallback chain（逗号分隔）。
   * - 无设置时返回第一个可用模型。
   * - 没有任何可用模型时返回兜底 'claude-sonnet-4-6'。
   */
  async getDefaultModel(userId: string, preferredChain?: string): Promise<string> {
    const available = await this.getAvailableModels(userId)
    const availableSet = new Set(available.filter((m) => m.status === 'available').map((m) => m.id))

    if (preferredChain) {
      const candidates = preferredChain
        .split(',')
        .map((s) => s.trim())
        .filter(Boolean)
      for (const id of candidates) {
        if (availableSet.has(id)) return id
      }
    }

    if (availableSet.size > 0) {
      return available.find((m) => m.status === 'available')!.id
    }

    return 'claude-sonnet-4-6'
  },
}
