import type {
  ProviderAdapter,
  ProviderCustomModel,
} from '#cli/compat/providers'
import {
  getAihubmixCapabilitiesForModelId,
  getAihubmixLimitForModelId,
} from '#cli/compat/providers'

export function parseCustomModelIds(draft: string): string[] {
  const raw = String(draft ?? '')
    .split(/[\n,]/u)
    .map((s) => s.trim())
    .filter(Boolean)
  const seen = new Set<string>()
  const next: string[] = []
  for (const id of raw) {
    if (seen.has(id)) continue
    seen.add(id)
    next.push(id)
  }
  return next
}

function shouldInferAihubmixLimit(
  adapter: ProviderAdapter | undefined,
): boolean {
  if (!adapter) return true
  return (
    adapter === 'openai' ||
    adapter === 'openai-responses' ||
    adapter === 'gemini' ||
    adapter === 'anthropic'
  )
}

function applyAihubmixLimits(
  models: ProviderCustomModel[],
  opts: Readonly<{ adapter?: ProviderAdapter; onlyIds?: Set<string> }>,
): ProviderCustomModel[] {
  if (!shouldInferAihubmixLimit(opts.adapter)) return models
  const onlyIds = opts.onlyIds
  return models.map((model) => {
    const id = String(model?.id ?? '').trim()
    if (!id) return model
    if (onlyIds && !onlyIds.has(id)) return model
    const currentLimit = model.limit ?? {}
    const hasContext =
      typeof currentLimit.context === 'number' &&
      Number.isFinite(currentLimit.context)
    const hasOutput =
      typeof currentLimit.output === 'number' &&
      Number.isFinite(currentLimit.output)
    if (hasContext && hasOutput) return model
    const inferred = getAihubmixLimitForModelId(id)
    if (!inferred) return model
    const nextLimit = { ...currentLimit }
    if (!hasContext && typeof inferred.context === 'number')
      nextLimit.context = inferred.context
    if (!hasOutput && typeof inferred.output === 'number')
      nextLimit.output = inferred.output
    if (!Object.keys(nextLimit).length) return model
    return { ...model, limit: nextLimit }
  })
}

function applyAihubmixCapabilities(
  models: ProviderCustomModel[],
  opts: Readonly<{ adapter?: ProviderAdapter; onlyIds?: Set<string> }>,
): ProviderCustomModel[] {
  if (!shouldInferAihubmixLimit(opts.adapter)) return models
  const onlyIds = opts.onlyIds
  return models.map((model) => {
    const id = String(model?.id ?? '').trim()
    if (!id) return model
    if (onlyIds && !onlyIds.has(id)) return model
    const hasVision = typeof model.vision === 'boolean'
    const hasReasoning = model.reasoning?.supported === true
    if (hasVision && hasReasoning) return model
    const inferred = getAihubmixCapabilitiesForModelId(id)
    if (!inferred) return model
    const updates: Partial<ProviderCustomModel> = {}
    if (!hasVision && typeof inferred.vision === 'boolean')
      updates.vision = inferred.vision
    if (!hasReasoning && inferred.reasoning?.supported)
      updates.reasoning = inferred.reasoning
    if (!Object.keys(updates).length) return model
    return { ...model, ...updates }
  })
}

export function buildCustomModelsFromIds(
  ids: string[],
  opts: Readonly<{
    existing?: ProviderCustomModel[]
    adapter?: ProviderAdapter
    inferNew?: boolean
  }>,
): ProviderCustomModel[] {
  const existing = Array.isArray(opts.existing) ? opts.existing : []
  const existingMap = new Map<string, ProviderCustomModel>()
  for (const model of existing) {
    const id = String(model?.id ?? '').trim()
    if (!id) continue
    if (!existingMap.has(id)) existingMap.set(id, model)
  }
  const seen = new Set<string>()
  const normalized: string[] = []
  for (const raw of ids) {
    const id = String(raw ?? '').trim()
    if (!id || seen.has(id)) continue
    seen.add(id)
    normalized.push(id)
  }
  const next: ProviderCustomModel[] = []
  const newIds = new Set<string>()
  for (const id of normalized) {
    const existingModel = existingMap.get(id)
    if (existingModel) {
      next.push(existingModel)
      continue
    }
    newIds.add(id)
    next.push({ id })
  }
  if (opts.inferNew) {
    const withLimits = applyAihubmixLimits(next, {
      adapter: opts.adapter,
      onlyIds: newIds,
    })
    return applyAihubmixCapabilities(withLimits, {
      adapter: opts.adapter,
      onlyIds: newIds,
    })
  }
  return next
}
