/**
 * Adapter 通用工具函数。
 */

import type { ConnectionTestResult, ModelCapabilities, ModelRecord, ProviderCredential } from '../types'

export async function fetchWithTimeout(
  url: string,
  init: RequestInit & { timeoutMs?: number } = {},
): Promise<Response> {
  const { timeoutMs = 15000, ...rest } = init
  return fetch(url, {
    ...rest,
    signal: AbortSignal.timeout(timeoutMs),
  })
}

export function bearerHeaders(credential: ProviderCredential): Record<string, string> {
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
  }
  if (credential.apiKey) {
    if (credential.authType === 'api_key') {
      headers['x-api-key'] = credential.apiKey
    } else {
      headers['Authorization'] = `Bearer ${credential.apiKey}`
    }
  }
  return headers
}

export function normalizeBaseUrl(baseUrl?: string, defaultUrl?: string): string {
  const url = (baseUrl || defaultUrl || '').trim().replace(/\/+$/, '')
  return url
}

/**
 * 用真实聊天协议做连接探测：Anthropic-compatible POST /v1/messages，max_tokens=1。
 * 与 Forge 运行时 resolveProvider 的对话路径一致。
 */
export async function testAnthropicCompatibleConnection(opts: {
  baseUrl: string
  apiKey: string
  /** 探针模型：任选一个较新的稳定模型即可 */
  model: string
  timeoutMs?: number
}): Promise<ConnectionTestResult> {
  if (!opts.apiKey) return { ok: false, error: 'No API key configured' }
  const baseUrl = normalizeBaseUrl(opts.baseUrl)
  if (!baseUrl) return { ok: false, error: 'Base URL is not configured' }

  try {
    const res = await fetchWithTimeout(`${baseUrl}/v1/messages`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${opts.apiKey}`,
        'anthropic-version': '2023-06-01',
      },
      body: JSON.stringify({
        model: opts.model,
        max_tokens: 1,
        messages: [{ role: 'user', content: 'hi' }],
      }),
      timeoutMs: opts.timeoutMs ?? 15000,
    })
    if (res.ok) return { ok: true }
    const data = (await res.json().catch(() => ({}))) as {
      error?: { message?: string }
      message?: string
    }
    return {
      ok: false,
      error: data.error?.message || data.message || `HTTP ${res.status}`,
    }
  } catch (err) {
    return { ok: false, error: err instanceof Error ? err.message : 'Connection failed' }
  }
}

const ANTHROPIC_MODEL_PATTERNS = [
  { test: /claude-opus-4-6|claude-opus-4-7|claude-opus-4-8/, label: 'Claude Opus', supportsThinking: true, supportsAdaptiveThinking: true, supportsEffort: true },
  { test: /claude-sonnet-4-6|claude-sonnet-4-7|claude-sonnet-4-8|claude-sonnet-5/, label: 'Claude Sonnet', supportsThinking: true, supportsAdaptiveThinking: true, supportsEffort: true },
  { test: /claude-fable-5/, label: 'Claude Fable', supportsThinking: true, supportsAdaptiveThinking: true, supportsEffort: true },
  { test: /claude-haiku-4-5|claude-haiku-4-6/, label: 'Claude Haiku', supportsThinking: false, supportsAdaptiveThinking: false, supportsEffort: false },
]

export function inferAnthropicCapabilities(modelId: string): ModelCapabilities {
  const matched = ANTHROPIC_MODEL_PATTERNS.find((p) => p.test.test(modelId))
  return {
    contextWindow: 200_000,
    maxOutputTokens: 8192,
    supportsVision: true,
    supportsThinking: matched?.supportsThinking ?? false,
    supportsAdaptiveThinking: matched?.supportsAdaptiveThinking ?? false,
    supportsEffort: matched?.supportsEffort ?? false,
    supportsFastMode: false,
    supportsAutoMode: false,
  }
}

export function buildAnthropicRecord(modelId: string, label?: string, providerName?: string, providerId = 'anthropic'): ModelRecord {
  return {
    id: modelId,
    label: label || modelId,
    providerId,
    providerName,
    capabilities: inferAnthropicCapabilities(modelId),
    source: 'seed',
  }
}

export function buildGenericRecord(
  modelId: string,
  label: string,
  providerId: string,
  providerName?: string,
  capabilities: ModelCapabilities = {},
): ModelRecord {
  return {
    id: modelId,
    label,
    providerId,
    providerName,
    capabilities,
    source: 'seed',
  }
}

/** OpenAI-compatible /models 响应结构 */
export interface OpenAIModelsResponse {
  data?: Array<{ id: string; object?: string }>
  object?: string
}

export function parseOpenAIModelsResponse(
  json: OpenAIModelsResponse,
  providerId: string,
  providerName: string,
  capabilitiesFn: (id: string) => ModelCapabilities,
): ModelRecord[] {
  const data = json.data || []
  return data.map((m) => ({
    id: m.id,
    label: m.id,
    providerId,
    providerName,
    capabilities: capabilitiesFn(m.id),
    source: 'dynamic',
  }))
}
