import type {
  GatewayDescriptor,
  TransportKind,
  ValidationRoutingMetadata,
  VendorDescriptor,
} from './descriptors.js'
import {
  ensureIntegrationsLoaded,
  getAllGateways,
  getAllVendors,
  getGateway,
  getVendor,
  resolveProfileRoute,
} from './index.js'
import { hasUsableOpenAICredential } from '../services/api/credentialPool.js'
import { isEnvTruthy } from '../utils/envUtils.js'

export type RouteDescriptor = GatewayDescriptor | VendorDescriptor

const TRANSPORT_KIND_PROVIDER_TYPE_LABELS: Partial<
  Record<TransportKind, string>
> = {
  'anthropic-native': 'Anthropic native API',
  'gemini-native': 'Gemini API',
  bedrock: 'AWS Bedrock Claude API',
  vertex: 'Google Vertex Claude API',
  'anthropic-proxy': 'Anthropic-compatible API',
  local: 'OpenAI-compatible API',
  'openai-compatible': 'OpenAI-compatible API',
}

const XIAOMI_MIMO_PRIMARY_HOST = 'api.xiaomimimo.com'
const XIAOMI_MIMO_STALE_DOCS_HOST = 'api.mimo-v2.com'
const XIAOMI_MIMO_TOKEN_PLAN_HOSTS = [
  'token-plan-sgp.xiaomimimo.com',
  'token-plan-cn.xiaomimimo.com',
]
export const XIAOMI_MIMO_PRIMARY_BASE_URL = `https://${XIAOMI_MIMO_PRIMARY_HOST}/v1`

function getValidationRoutingHosts(
  descriptor: RouteDescriptor,
): string[] {
  const routing = descriptor.validation?.routing as
    | ValidationRoutingMetadata
    | undefined
  return routing?.matchBaseUrlHosts ?? []
}

export function matchHostnameAgainstRouteHosts(
  hostname: string,
  routeHosts: string[],
): boolean {
  return routeHosts.some(host => {
    const lowerHost = host.toLowerCase()
    if (lowerHost.startsWith('*.')) {
      const suffix = lowerHost.slice(1)
      return hostname.endsWith(suffix)
    }
    return hostname === lowerHost
  })
}

function normalizeComparableBaseUrl(
  baseUrl?: string,
): string | null {
  if (!baseUrl?.trim()) {
    return null
  }

  try {
    const parsed = new URL(baseUrl)
    parsed.hash = ''
    parsed.search = ''
    return parsed.toString().replace(/\/+$/, '').toLowerCase()
  } catch {
    return baseUrl.trim().replace(/\/+$/, '').toLowerCase() || null
  }
}

function normalizeHost(
  baseUrl?: string,
): string | null {
  if (!baseUrl?.trim()) {
    return null
  }

  try {
    return new URL(baseUrl).hostname.toLowerCase()
  } catch {
    return null
  }
}

function getAllRoutes(): RouteDescriptor[] {
  ensureIntegrationsLoaded()
  return [...getAllGateways(), ...getAllVendors()]
}

function resolveKnownLocalRouteIdFromBaseUrl(baseUrl?: string): string | null {
  if (!baseUrl) {
    return null
  }

  try {
    const parsed = new URL(baseUrl)
    const host = parsed.host.toLowerCase()
    const hostname = parsed.hostname.toLowerCase()
    const path = parsed.pathname.toLowerCase()
    const haystack = `${hostname} ${path}`

    if (host.endsWith(':11434') || haystack.includes('ollama')) {
      return 'ollama'
    }
    if (
      host.endsWith(':1234') ||
      haystack.includes('lmstudio') ||
      haystack.includes('lm-studio')
    ) {
      return 'lmstudio'
    }
  } catch {
    return null
  }

  return null
}

export function getRouteDescriptor(
  routeId: string,
): RouteDescriptor | null {
  ensureIntegrationsLoaded()
  return getGateway(routeId) ?? getVendor(routeId) ?? null
}

export function getRouteLabel(
  routeId: string,
): string | null {
  return getRouteDescriptor(routeId)?.label ?? null
}

export function getRouteDefaultBaseUrl(
  routeId: string,
): string | undefined {
  return getRouteDescriptor(routeId)?.defaultBaseUrl
}

export function getRouteDefaultModel(
  routeId: string,
): string | undefined {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return undefined
  }

  if ('defaultModel' in descriptor && descriptor.defaultModel) {
    return descriptor.defaultModel
  }

  const catalogModels = descriptor.catalog?.models ?? []
  const defaultEntry =
    catalogModels.find(model => model.default) ?? catalogModels[0]

  return defaultEntry?.apiName
}

/**
 * True for native vendor routes (e.g. MiniMax, xAI) that ship a complete,
 * curated static catalog. For these the catalog is authoritative, so the
 * `/model` picker should surface every catalogued model — not collapse to the
 * single model pinned in the active provider profile. Gateways, whose catalog
 * is a user-curated subset, keep the profile model list as a whitelist.
 */
export function isNativeVendorCatalogRoute(routeId: string): boolean {
  const vendor = getVendor(routeId)
  return (
    vendor?.classification === 'native' &&
    vendor.catalog?.source === 'static' &&
    (vendor.catalog?.models?.length ?? 0) > 0
  )
}

function uniqueEnvVars(envVars: Iterable<string>): string[] {
  const seen = new Set<string>()
  const normalized: string[] = []

  for (const envVar of envVars) {
    const trimmed = envVar.trim()
    if (!trimmed || seen.has(trimmed)) {
      continue
    }

    seen.add(trimmed)
    normalized.push(trimmed)
  }

  return normalized
}

function readFirstNonEmptyEnvValue(
  processEnv: NodeJS.ProcessEnv,
  envVars: readonly string[],
): string | undefined {
  for (const envVar of envVars) {
    const value = processEnv[envVar]
    if (hasUsableEnvCredentialValue(envVar, value)) {
      return value!.trim()
    }
  }

  return undefined
}

function hasUsableEnvCredentialValue(
  envVar: string,
  value: string | undefined,
): boolean {
  if (typeof value !== 'string') {
    return false
  }

  if (envVar === 'OPENAI_API_KEYS' || envVar === 'OPENAI_API_KEY') {
    return hasUsableOpenAICredential(value)
  }
  return value.trim() !== ''
}

function hasAnyUsableOpenAICredential(processEnv: NodeJS.ProcessEnv): boolean {
  return (
    hasUsableEnvCredentialValue('OPENAI_API_KEYS', processEnv.OPENAI_API_KEYS) ||
    hasUsableEnvCredentialValue('OPENAI_API_KEY', processEnv.OPENAI_API_KEY)
  )
}

function hasNonEmptyEnvValue(value: string | undefined): boolean {
  const trimmed = value?.trim().toLowerCase()
  return Boolean(trimmed && trimmed !== 'undefined' && trimmed !== 'null')
}

export function isMiniMaxBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    const hostname = new URL(trimmed).hostname.toLowerCase()
    return hostname === 'api.minimax.io' || hostname === 'api.minimax.chat'
  } catch {
    return false
  }
}

export function isXaiBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    return new URL(trimmed).hostname.toLowerCase() === 'api.x.ai'
  } catch {
    return false
  }
}

export function isXiaomiMimoBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    const hostname = new URL(trimmed).hostname.toLowerCase()
    return (
      hostname === XIAOMI_MIMO_PRIMARY_HOST ||
      hostname === XIAOMI_MIMO_STALE_DOCS_HOST ||
      XIAOMI_MIMO_TOKEN_PLAN_HOSTS.includes(hostname)
    )
  } catch {
    return false
  }
}

export function normalizeXiaomiMimoBaseUrl(
  value: string | undefined,
): string | undefined {
  const trimmed = value?.trim()
  if (!trimmed) {
    return undefined
  }

  try {
    const hostname = new URL(trimmed).hostname.toLowerCase()
    if (hostname === XIAOMI_MIMO_STALE_DOCS_HOST) {
      return XIAOMI_MIMO_PRIMARY_BASE_URL
    }
  } catch {
    return trimmed
  }

  return trimmed
}

export function getXiaomiMimoBaseUrlOverride(
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  const openAIBaseUrl = processEnv.OPENAI_BASE_URL?.trim()
  if (isXiaomiMimoBaseUrl(openAIBaseUrl)) {
    return normalizeXiaomiMimoBaseUrl(openAIBaseUrl)
  }

  const openAIApiBase = processEnv.OPENAI_API_BASE?.trim()
  if (isXiaomiMimoBaseUrl(openAIApiBase)) {
    return normalizeXiaomiMimoBaseUrl(openAIApiBase)
  }

  return undefined
}

export function isVeniceBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    return new URL(trimmed).hostname.toLowerCase() === 'api.venice.ai'
  } catch {
    return false
  }
}

export function isNearaiBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    const hostname = new URL(trimmed).hostname.toLowerCase()
    return hostname === 'cloud-api.near.ai' || hostname === 'completions.near.ai' || hostname.endsWith('.completions.near.ai')
  } catch {
    return false
  }
}

/**
 * Checks whether the given URL value targets the Fireworks AI inference API
 * by matching the hostname against `api.fireworks.ai`.
 */
export function isFireworksBaseUrl(value: string | undefined): boolean {
  const trimmed = value?.trim()
  if (!trimmed) {
    return false
  }

  try {
    return new URL(trimmed).hostname.toLowerCase() === 'api.fireworks.ai'
  } catch {
    return false
  }
}

export function getNearaiBaseUrlOverride(
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  const openAIBaseUrl = processEnv.OPENAI_BASE_URL?.trim()
  if (isNearaiBaseUrl(openAIBaseUrl)) {
    return openAIBaseUrl
  }

  const openAIApiBase = processEnv.OPENAI_API_BASE?.trim()
  if (isNearaiBaseUrl(openAIApiBase)) {
    return openAIApiBase
  }

  return undefined
}

/**
 * Returns the user-configured Fireworks AI base URL from `OPENAI_BASE_URL`
 * or `OPENAI_API_BASE` when the hostname resolves to api.fireworks.ai.
 */
export function getFireworksBaseUrlOverride(
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  const openAIBaseUrl = processEnv.OPENAI_BASE_URL?.trim()
  if (isFireworksBaseUrl(openAIBaseUrl)) {
    return openAIBaseUrl
  }

  const openAIApiBase = processEnv.OPENAI_API_BASE?.trim()
  if (isFireworksBaseUrl(openAIApiBase)) {
    return openAIApiBase
  }

  return undefined
}
export function getMiniMaxBaseUrlOverride(
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  const anthropicBaseUrl = processEnv.ANTHROPIC_BASE_URL?.trim()
  if (isMiniMaxBaseUrl(anthropicBaseUrl)) {
    return anthropicBaseUrl
  }

  const openAIBaseUrl = processEnv.OPENAI_BASE_URL?.trim()
  if (isMiniMaxBaseUrl(openAIBaseUrl)) {
    return openAIBaseUrl
  }

  const openAIApiBase = processEnv.OPENAI_API_BASE?.trim()
  if (isMiniMaxBaseUrl(openAIApiBase)) {
    return openAIApiBase
  }

  return undefined
}

function isMiniMaxModelName(value: string | undefined): boolean {
  const normalized = value?.trim().toLowerCase()
  return Boolean(
    normalized &&
      (normalized.startsWith('minimax-') || normalized.startsWith('minimax/')),
  )
}

function hasMiniMaxRouteIntent(processEnv: NodeJS.ProcessEnv): boolean {
  return (
    getMiniMaxBaseUrlOverride(processEnv) !== undefined ||
    isMiniMaxModelName(processEnv.OPENAI_MODEL) ||
    isMiniMaxModelName(processEnv.ANTHROPIC_MODEL)
  )
}

export function getXaiBaseUrlOverride(
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  const openAIBaseUrl = processEnv.OPENAI_BASE_URL?.trim()
  if (isXaiBaseUrl(openAIBaseUrl)) {
    return openAIBaseUrl
  }

  const openAIApiBase = processEnv.OPENAI_API_BASE?.trim()
  if (isXaiBaseUrl(openAIApiBase)) {
    return openAIApiBase
  }

  return undefined
}

function hasConflictingOpenAIBaseUrlForRoute(
  processEnv: NodeJS.ProcessEnv,
  isRouteBaseUrl: (value: string | undefined) => boolean,
): boolean {
  if (hasNonEmptyEnvValue(processEnv.OPENAI_BASE_URL)) {
    return !isRouteBaseUrl(processEnv.OPENAI_BASE_URL)
  }

  return (
    hasNonEmptyEnvValue(processEnv.OPENAI_API_BASE) &&
    !isRouteBaseUrl(processEnv.OPENAI_API_BASE)
  )
}

function hasNoExplicitNonOpenAICompatibleProvider(
  processEnv: NodeJS.ProcessEnv,
): boolean {
  return (
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_GITHUB) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_GEMINI) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_MISTRAL) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_BEDROCK) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_VERTEX) &&
    !isEnvTruthy(processEnv.CLAUDE_CODE_USE_FOUNDRY)
  )
}

export function hasXaiEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isXaiBaseUrl) &&
    hasNoExplicitNonOpenAICompatibleProvider(processEnv)
  )
}

export function hasMiniMaxEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  const hasExplicitMiniMaxIntent = hasMiniMaxRouteIntent(processEnv)
  const hasMiniMaxCredential =
    hasNonEmptyEnvValue(processEnv.MINIMAX_API_KEY) ||
    (isMiniMaxBaseUrl(processEnv.ANTHROPIC_BASE_URL) &&
      hasNonEmptyEnvValue(processEnv.ANTHROPIC_API_KEY))

  return (
    hasMiniMaxCredential &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isMiniMaxBaseUrl) &&
    (hasExplicitMiniMaxIntent ||
      (!hasAnyUsableOpenAICredential(processEnv) &&
        !hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
        hasNoExplicitNonOpenAICompatibleProvider(processEnv)))
  )
}

export function hasVeniceEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    hasNonEmptyEnvValue(processEnv.VENICE_API_KEY) &&
    !hasAnyUsableOpenAICredential(processEnv) &&
    !hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MINIMAX_API_KEY) &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isVeniceBaseUrl) &&
    hasNoExplicitNonOpenAICompatibleProvider(processEnv)
  )
}

export function hasXiaomiMimoEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    hasNonEmptyEnvValue(processEnv.MIMO_API_KEY) &&
    !hasAnyUsableOpenAICredential(processEnv) &&
    !hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MINIMAX_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.VENICE_API_KEY) &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isXiaomiMimoBaseUrl) &&
    hasNoExplicitNonOpenAICompatibleProvider(processEnv)
  )
}

export function hasNearaiEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    hasNonEmptyEnvValue(processEnv.NEARAI_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MINIMAX_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.VENICE_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MIMO_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.FIREWORKS_API_KEY) &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isNearaiBaseUrl) &&
    hasNoExplicitNonOpenAICompatibleProvider(processEnv)
  )
}

/**
 * Detects whether the process environment is configured to route traffic
 * exclusively through Fireworks AI based on the presence of FIREWORKS_API_KEY
 * and the absence of conflicting env vars for other providers.
 */
export function hasFireworksEnvOnlyProviderIntent(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    hasNonEmptyEnvValue(processEnv.FIREWORKS_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.XAI_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MINIMAX_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.VENICE_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.MIMO_API_KEY) &&
    !hasNonEmptyEnvValue(processEnv.NEARAI_API_KEY) &&
    !hasConflictingOpenAIBaseUrlForRoute(processEnv, isFireworksBaseUrl) &&
    hasNoExplicitNonOpenAICompatibleProvider(processEnv)
  )
}

export function resolveEnvOnlyProviderRouteId(
  processEnv: NodeJS.ProcessEnv = process.env,
): 'xai' | 'minimax' | 'venice' | 'xiaomi-mimo' | 'nearai' | 'fireworks' | null {
  if (
    hasMiniMaxRouteIntent(processEnv) &&
    hasMiniMaxEnvOnlyProviderIntent(processEnv)
  ) {
    return 'minimax'
  }

  if (hasXaiEnvOnlyProviderIntent(processEnv)) {
    return 'xai'
  }

  if (hasMiniMaxEnvOnlyProviderIntent(processEnv)) {
    return 'minimax'
  }

  if (hasVeniceEnvOnlyProviderIntent(processEnv)) {
    return 'venice'
  }

  if (hasXiaomiMimoEnvOnlyProviderIntent(processEnv)) {
    return 'xiaomi-mimo'
  }

  if (hasNearaiEnvOnlyProviderIntent(processEnv)) {
    return 'nearai'
  }

  if (hasFireworksEnvOnlyProviderIntent(processEnv)) {
    return 'fireworks'
  }

  return null
}

export function getRouteCredentialEnvVars(
  routeId: string,
): string[] {
  if (routeId === 'custom') {
    return ['OPENAI_API_KEYS', 'OPENAI_API_KEY']
  }

  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return []
  }

  const envVars = [...(descriptor.setup.credentialEnvVars ?? [])]
  if (
    (descriptor.transportConfig.kind === 'openai-compatible' ||
      descriptor.transportConfig.kind === 'local') &&
    !descriptor.setup.dedicatedCredentialsOnly &&
    !envVars.includes('OPENAI_API_KEYS')
  ) {
    const openAIFallbackIndex = envVars.indexOf('OPENAI_API_KEY')
    if (openAIFallbackIndex === -1) {
      envVars.push('OPENAI_API_KEYS', 'OPENAI_API_KEY')
    } else {
      envVars.splice(openAIFallbackIndex, 0, 'OPENAI_API_KEYS')
    }
  }

  return uniqueEnvVars(envVars)
}

export function getRouteCredentialValue(
  routeId: string,
  processEnv: NodeJS.ProcessEnv = process.env,
): string | undefined {
  return readFirstNonEmptyEnvValue(
    processEnv,
    getRouteCredentialEnvVars(routeId),
  )
}

export function resolveRouteCredentialValue(
  options?: {
    routeId?: string | null
    baseUrl?: string
    processEnv?: NodeJS.ProcessEnv
    activeProfileProvider?: string
  },
): string | undefined {
  const processEnv = options?.processEnv ?? process.env
  const routeId =
    options?.routeId ??
    resolveActiveRouteIdFromEnv(processEnv, {
      activeProfileProvider: options?.activeProfileProvider,
    }) ??
    resolveRouteIdFromBaseUrl(options?.baseUrl) ??
    (options?.baseUrl ? 'custom' : null)

  if (!routeId || routeId === 'anthropic') {
    return undefined
  }

  return getRouteCredentialValue(routeId, processEnv)
}

export function routeSupportsCustomHeaders(
  routeId: string,
): boolean {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return false
  }

  return descriptor.transportConfig.openaiShim?.supportsAuthHeaders === true
}

export function routeShowsAuthHeaderValue(routeId: string): boolean {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return false
  }

  return (
    descriptor.transportConfig.openaiShim?.supportsAuthHeaders === true &&
    descriptor.transportConfig.openaiShim?.ui?.showAuthHeaderValue !== false
  )
}

export function routeShowsAuthHeader(routeId: string): boolean {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return false
  }

  return (
    descriptor.transportConfig.openaiShim?.supportsAuthHeaders === true &&
    descriptor.transportConfig.openaiShim?.ui?.showAuthHeader !== false
  )
}

export function routeShowsCustomHeaders(routeId: string): boolean {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor) {
    return false
  }

  return (
    routeSupportsCustomHeaders(routeId) &&
    descriptor.transportConfig.openaiShim?.ui?.showCustomHeaders !== false
  )
}

function routeSupportsOpenAIShimOption(
  routeId: string,
  option: 'supportsApiFormatSelection' | 'supportsAuthHeaders',
): boolean {
  const descriptor = getRouteDescriptor(routeId)
  if (!descriptor || descriptor.transportConfig.kind !== 'openai-compatible') {
    return false
  }

  return descriptor.transportConfig.openaiShim?.[option] === true
}

export function routeSupportsApiFormatSelection(routeId: string): boolean {
  return routeSupportsOpenAIShimOption(routeId, 'supportsApiFormatSelection')
}

export function routeSupportsAuthHeaders(routeId: string): boolean {
  return routeSupportsOpenAIShimOption(routeId, 'supportsAuthHeaders')
}

export function getRouteProviderTypeLabel(
  routeId: string,
): string {
  const kind = getRouteDescriptor(routeId)?.transportConfig.kind
  return (
    (kind ? TRANSPORT_KIND_PROVIDER_TYPE_LABELS[kind] : undefined) ??
    'OpenAI-compatible API'
  )
}

export function resolveRouteIdFromBaseUrl(
  baseUrl?: string,
  options?: {
    requireDiscovery?: boolean
  },
): string | null {
  const normalizedBaseUrl = normalizeComparableBaseUrl(baseUrl)
  const normalizedHost = normalizeHost(baseUrl)
  if (!normalizedBaseUrl && !normalizedHost) {
    return null
  }

  const routes = getAllRoutes().filter(route =>
    options?.requireDiscovery ? Boolean(route.catalog?.discovery) : true,
  )

  for (const route of routes) {
    const normalizedDefaultBaseUrl = normalizeComparableBaseUrl(
      route.defaultBaseUrl,
    )
    if (
      normalizedBaseUrl &&
      normalizedDefaultBaseUrl === normalizedBaseUrl
    ) {
      return route.id
    }
  }

  if (normalizedHost) {
    for (const route of routes) {
      if (matchHostnameAgainstRouteHosts(normalizedHost, getValidationRoutingHosts(route))) {
        return route.id
      }
    }
  }

  const localRouteId = resolveKnownLocalRouteIdFromBaseUrl(baseUrl)
  if (localRouteId) {
    return localRouteId
  }

  return null
}

export function resolveActiveRouteIdFromEnv(
  processEnv: NodeJS.ProcessEnv = process.env,
  options?: {
    activeProfileProvider?: string
  },
): string | null {
  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_GEMINI)) {
    return 'gemini'
  }
  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_MISTRAL)) {
    return 'mistral'
  }
  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_GITHUB)) {
    return 'github'
  }
  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_BEDROCK)) {
    return 'bedrock'
  }
  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_VERTEX)) {
    return 'vertex'
  }

  const envOnlyRouteId = resolveEnvOnlyProviderRouteId(processEnv)
  if (envOnlyRouteId) return envOnlyRouteId

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI)) {
    const baseUrl =
      processEnv.OPENAI_BASE_URL ?? processEnv.OPENAI_API_BASE
    const matchedRoute = resolveRouteIdFromBaseUrl(baseUrl)

    if (
      processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1' &&
      options?.activeProfileProvider
    ) {
      const route = resolveProfileRoute(options.activeProfileProvider)
      if (
        route.routeId !== 'unknown-fallback' &&
        route.routeId !== 'openai' &&
        route.routeId !== 'custom'
      ) {
        return route.routeId
      }
    }

    if (matchedRoute) {
      return matchedRoute
    }

    const normalizedBaseUrl = normalizeComparableBaseUrl(baseUrl)
    const openAIDefaultBaseUrl = normalizeComparableBaseUrl(
      getRouteDefaultBaseUrl('openai'),
    )

    if (!normalizedBaseUrl || normalizedBaseUrl === openAIDefaultBaseUrl) {
      return 'openai'
    }

    return 'custom'
  }

  return 'anthropic'
}

export function getTransportKindForRoute(
  routeId: string,
): TransportKind | null {
  return getRouteDescriptor(routeId)?.transportConfig.kind ?? null
}
