import { NextRequest, NextResponse } from 'next/server'
import { apiProviderRepo } from '@/lib/database/repositories/api-provider.repo'
import { isClaudeCliAuthenticated } from '@/lib/provider'
import { modelRegistry } from '@/lib/engine/model-registry'
import { isAuthError, requireUser } from '@/lib/auth/session'
import { getBuiltinApiProvider } from '@/lib/api-provider-catalog'

/**
 * POST /api/api-providers/:id/test
 *
 * 测试连接：
 * - Anthropic 无 key：CLI 认证探测（claude --version）
 * - 其它有 key：委托 modelRegistry → adapter.testConnection
 *   （moonshot/zhipu/minimax/qwen/deepseek 走 Anthropic Messages 最小请求）
 * - 成功后异步刷新模型列表
 */
export async function POST(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
  let user
  try {
    user = await requireUser()
  } catch (err) {
    if (isAuthError(err)) return err
    throw err
  }
  const { id } = await params

  const provider = apiProviderRepo.findRawByIdAndUser(id, user.id)
  if (!provider) {
    const builtin = getBuiltinApiProvider(id)
    if (!builtin) return NextResponse.json({ error: 'Provider not found' }, { status: 404 })
    apiProviderRepo.upsertBuiltin(id, builtin.name, user.id)
  }
  const providerRow = provider ?? apiProviderRepo.findRawByIdAndUser(id, user.id)
  if (!providerRow) return NextResponse.json({ error: 'Provider not found' }, { status: 404 })

  // For Anthropic: if no API key, check CLI auth
  if (!providerRow.apiKey) {
    if (providerRow.provider === 'anthropic' && isClaudeCliAuthenticated()) {
      try {
        const ok = await testViaCliAuth()
        const status = ok ? 'cli_authenticated' : 'error'
        const errorMsg = ok ? '' : 'CLI authentication test failed'
        apiProviderRepo.updateStatus(id, user.id, status, errorMsg)
        const updated = apiProviderRepo.findByIdAndUser(id, user.id)
        return NextResponse.json(updated)
      } catch (err) {
        const errorMsg = err instanceof Error ? err.message : 'CLI auth test failed'
        apiProviderRepo.updateStatus(id, user.id, 'error', errorMsg)
        const updated = apiProviderRepo.findByIdAndUser(id, user.id)
        return NextResponse.json(updated)
      }
    }

    apiProviderRepo.updateStatus(id, user.id, 'not_configured', '')
    const updated = apiProviderRepo.findByIdAndUser(id, user.id)
    return NextResponse.json(updated)
  }

  try {
    let ok = false
    let errorMsg = ''

    if (providerRow.provider === 'anthropic') {
      // Anthropic API key：保持原有最小 messages 探测（x-api-key）
      const baseUrl = providerRow.baseUrl || 'https://api.anthropic.com'
      const res = await fetch(`${baseUrl}/v1/messages`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': providerRow.apiKey,
          'anthropic-version': '2023-06-01',
        },
        body: JSON.stringify({
          model: 'claude-haiku-4-5-20251001',
          max_tokens: 1,
          messages: [{ role: 'user', content: 'hi' }],
        }),
        signal: AbortSignal.timeout(15000),
      })

      if (res.ok) {
        ok = true
      } else {
        const data = await res.json().catch(() => ({}))
        errorMsg = (data as { error?: { message?: string } }).error?.message || `HTTP ${res.status}`
      }
    } else if (providerRow.provider === 'stt') {
      // STT：语音服务，测 OpenAI-compatible /models
      const baseUrl = (providerRow.baseUrl || '').replace(/\/+$/, '')
      if (!baseUrl) {
        ok = false
        errorMsg = 'Base URL is not configured'
      } else {
        const url = baseUrl.includes('/v1') ? `${baseUrl}/models` : `${baseUrl}/v1/models`
        const headers: Record<string, string> = {}
        if (providerRow.apiKey) headers['Authorization'] = `Bearer ${providerRow.apiKey}`
        const res = await fetch(url, { headers, signal: AbortSignal.timeout(15000) })
        if (res.ok) {
          ok = true
        } else {
          const data = await res.json().catch(() => ({}))
          errorMsg = (data as { error?: { message?: string } }).error?.message || `HTTP ${res.status}`
        }
      }
    } else {
      // moonshot / zhipu / minimax / qwen / deepseek / custom …
      // 委托 adapter：国产 LLM 走 Anthropic-compatible 最小 messages
      const result = await modelRegistry.testProviderConnection(id, user.id)
      ok = result.ok
      errorMsg = result.error || ''
    }

    const status = ok ? 'connected' : 'error'
    apiProviderRepo.updateStatus(id, user.id, status, errorMsg)

    if (ok && providerRow.provider !== 'stt') {
      // 连接成功后异步刷新该 provider 的模型列表，失败不影响返回结果
      modelRegistry.refreshProviderModels(id, user.id).catch((e) => {
        console.warn(
          `[testProvider] refresh models failed for ${id}:`,
          e instanceof Error ? e.message : e,
        )
      })
    }

    const updated = apiProviderRepo.findByIdAndUser(id, user.id)
    return NextResponse.json(updated)
  } catch (err) {
    const errorMsg = err instanceof Error ? err.message : 'Connection failed'
    apiProviderRepo.updateStatus(id, user.id, 'error', errorMsg)
    const updated = apiProviderRepo.findByIdAndUser(id, user.id)
    return NextResponse.json(updated)
  }
}

/**
 * Test CLI authentication by spawning a minimal Claude Code SDK query.
 * Uses `claude --version` as a lightweight check — if the CLI can authenticate, it succeeds.
 */
async function testViaCliAuth(): Promise<boolean> {
  const { execFile } = await import('child_process')
  const { promisify } = await import('util')
  const execFileAsync = promisify(execFile)
  const fs = await import('fs')
  const path = await import('path')
  const os = await import('os')

  try {
    let claudePath: string | null = null
    const which = await execFileAsync('which', ['claude']).catch(() => null)
    if (which?.stdout?.trim()) {
      claudePath = which.stdout.trim()
    } else {
      const candidates = [
        path.join(os.homedir(), '.local', 'bin', 'claude'),
        '/usr/local/bin/claude',
        '/opt/homebrew/bin/claude',
      ]
      for (const c of candidates) {
        if (fs.existsSync(c)) {
          claudePath = c
          break
        }
      }
    }

    if (!claudePath) return false

    await execFileAsync(claudePath, ['--version'], { timeout: 10000 })
    return true
  } catch {
    return false
  }
}
