import { randomBytes } from 'crypto'
import {
  getAdditionalModelOptionsCacheScope,
  isCodexBaseUrl,
  parseOpenAICompatibleApiFormat,
} from '../services/api/providerConfig.js'
import {
  getGlobalConfig,
  saveGlobalConfig,
  type ProviderProfile,
} from './config.js'
import type { ModelOption } from './model/modelOptions.js'
import { getPrimaryModel, parseModelList } from './providerModels.js'
import {
  buildCompatibilityProcessEnv,
  createProfileFile,
  saveProfileFile,
  buildBedrockProfileEnv,
  buildGeminiProfileEnv,
  buildGithubProfileEnv,
  buildMiniMaxProfileEnv,
  buildMistralProfileEnv,
  buildNvidiaNimProfileEnv,
  buildOpenAIProfileEnv,
  buildVeniceProfileEnv,
  buildXaiOAuthProfileEnv,
  buildXiaomiMimoProfileEnv,
  buildAtlasCloudProfileEnv,
  buildVertexProfileEnv,
  clearManagedProfileEnv,
  type ProfileFileLocation,
  type ProfileEnv,
  type ProviderProfile as ProviderProfileStartup,
} from './providerProfile.js'
import { refreshStartupDiscoveryForRoute } from '../integrations/discoveryService.js'
import {
  getCatalogEntriesForRoute,
  getProviderPresetUiMetadata,
  normalizeXiaomiMimoBaseUrl,
  routeSupportsApiFormatSelection,
  routeSupportsAuthHeaders,
  routeSupportsCustomHeaders,
  resolveProfileRoute,
  resolveRouteIdFromBaseUrl,
  type ResolvedProfileRoute,
  type ProviderPreset,
} from '../integrations/index.js'
import {
  isFireworksBaseUrl,
  isNearaiBaseUrl,
  isXaiBaseUrl,
  isXiaomiMimoBaseUrl,
  resolveEnvOnlyProviderRouteId,
} from '../integrations/routeMetadata.js'
import { logForDebugging } from './debug.js'
import {
  sanitizeProfileCustomHeaders,
  serializeProfileCustomHeaders,
} from './providerCustomHeaders.js'
import { getSettings_DEPRECATED } from './settings/settings.js'

export type { ProviderPreset } from '../integrations/index.js'

export type ProviderProfileInput = {
  provider?: ProviderProfile['provider']
  name: string
  baseUrl: string
  model: string
  apiKey?: string
  apiFormat?: ProviderProfile['apiFormat']
  authHeader?: ProviderProfile['authHeader']
  authScheme?: ProviderProfile['authScheme']
  authHeaderValue?: ProviderProfile['authHeaderValue']
  customHeaders?: ProviderProfile['customHeaders']
  maxContextLength?: ProviderProfile['maxContextLength']
}

export type ProviderPresetDefaults = Omit<ProviderProfileInput, 'provider'> & {
  provider: ProviderProfile['provider']
  requiresApiKey: boolean
}

const PROFILE_ENV_APPLIED_FLAG = 'CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED'
const PROFILE_ENV_APPLIED_ID = 'CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID'

type ProfileCompatibilityMode =
  | 'anthropic'
  | 'gemini'
  | 'mistral'
  | 'github'
  | 'github-enterprise'
  | 'bedrock'
  | 'vertex'
  | 'openai'

function isGithubCompatibilityMode(
  compatibilityMode: ProfileCompatibilityMode,
): boolean {
  return (
    compatibilityMode === 'github' ||
    compatibilityMode === 'github-enterprise'
  )
}

function resolveProfileCompatibility(provider: string): {
  route: ResolvedProfileRoute
  compatibilityMode: ProfileCompatibilityMode
} {
  const route = resolveProfileRoute(provider)

  if (provider === 'github-enterprise' || route.gatewayId === 'github-enterprise') {
    return { route, compatibilityMode: 'github-enterprise' }
  }
  if (provider === 'github' || route.gatewayId === 'github') {
    return { route, compatibilityMode: 'github' }
  }
  if (route.gatewayId === 'bedrock') {
    return { route, compatibilityMode: 'bedrock' }
  }
  if (route.gatewayId === 'vertex') {
    return { route, compatibilityMode: 'vertex' }
  }
  if (route.vendorId === 'anthropic') {
    return { route, compatibilityMode: 'anthropic' }
  }
  if (route.vendorId === 'minimax') {
    return { route, compatibilityMode: 'anthropic' }
  }
  if (route.vendorId === 'gemini') {
    return { route, compatibilityMode: 'gemini' }
  }
  if (route.vendorId === 'mistral' || route.gatewayId === 'mistral') {
    return { route, compatibilityMode: 'mistral' }
  }

  return { route, compatibilityMode: 'openai' }
}

function deriveGithubEnterpriseUrl(baseUrl: string | undefined): string | undefined {
  if (!baseUrl?.trim()) return undefined
  try {
    const parsed = new URL(baseUrl)
    if (parsed.origin === 'https://api.githubcopilot.com') {
      return undefined
    }
    return parsed.origin
  } catch {
    return undefined
  }
}

function buildGithubCompatibleProfileEnv(options: {
  model: string
  baseUrl?: string
  gatewayId?: string
  apiKey?: string
}): ProfileEnv {
  const env = buildGithubProfileEnv({
    model: options.model,
    baseUrl: options.baseUrl,
  })

  if (options.gatewayId === 'github-enterprise') {
    const enterpriseUrl = deriveGithubEnterpriseUrl(options.baseUrl)
    if (enterpriseUrl) {
      env.GITHUB_ENTERPRISE_URL = enterpriseUrl
    }
    if (options.apiKey?.trim()) {
      env.GITHUB_COPILOT_KEY = options.apiKey.trim()
    }
  }

  return env
}

function trimValue(value: string | undefined): string {
  return value?.trim() ?? ''
}

function trimOrUndefined(value: string | undefined): string | undefined {
  const trimmed = trimValue(value)
  return trimmed.length > 0 ? trimmed : undefined
}

function sanitizeAuthHeader(value: string | undefined): string | undefined {
  const trimmed = trimOrUndefined(value)
  if (!trimmed) {
    return undefined
  }
  return /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/.test(trimmed)
    ? trimmed
    : undefined
}

function sanitizeAuthScheme(value: string | undefined): ProviderProfile['authScheme'] | undefined {
  return value === 'raw' || value === 'bearer' ? value : undefined
}

function normalizeBaseUrl(value: string): string {
  return trimValue(value).replace(/\/+$/, '')
}

function resolveProfileCapabilityRouteId(
  provider: string,
  baseUrl?: string,
): string {
  return (
    resolveRouteIdFromBaseUrl(baseUrl) ??
    resolveProfileRoute(provider).routeId
  )
}

function normalizeProfileModelLookupKey(model: string | undefined): string {
  return model?.trim().split('?', 1)[0]?.trim().toLowerCase() ?? ''
}

function profileSupportsModel(profile: ProviderProfile, model: string): boolean {
  const normalizedModel = normalizeProfileModelLookupKey(model)
  if (!normalizedModel) {
    return false
  }

  if (
    parseModelList(profile.model).some(
      configured => normalizeProfileModelLookupKey(configured) === normalizedModel,
    )
  ) {
    return true
  }

  const routeId = resolveProfileCapabilityRouteId(profile.provider, profile.baseUrl)
  return getCatalogEntriesForRoute(routeId).some(
    entry =>
      normalizeProfileModelLookupKey(entry.apiName) === normalizedModel ||
      normalizeProfileModelLookupKey(entry.id) === normalizedModel ||
      (entry.aliases ?? []).some(
        alias => normalizeProfileModelLookupKey(alias) === normalizedModel,
      ),
  )
}

let savedModelOverrideForTesting: string | undefined

export function _setSavedModelOverrideForTesting(model: string | undefined): void {
  savedModelOverrideForTesting = model
}

function getSavedModelOverrideForProfile(
  profile: ProviderProfile,
): string | undefined {
  const savedModel = trimOrUndefined(
    savedModelOverrideForTesting ?? getSettings_DEPRECATED()?.model,
  )
  if (!savedModel || !profileSupportsModel(profile, savedModel)) {
    return undefined
  }

  return savedModel
}

function sanitizeProfile(profile: ProviderProfile): ProviderProfile | null {
  const id = trimValue(profile.id)
  const name = trimValue(profile.name)
  const provider = trimValue(profile.provider)
  const baseUrl = normalizeBaseUrl(profile.baseUrl)
  const model = trimValue(profile.model)
  const apiFormat = parseOpenAICompatibleApiFormat(profile.apiFormat)
  const authHeader = sanitizeAuthHeader(profile.authHeader)
  const authScheme = sanitizeAuthScheme(profile.authScheme)
  const authHeaderValue = trimOrUndefined(profile.authHeaderValue)
  const capabilityRouteId = resolveProfileCapabilityRouteId(provider, baseUrl)
  const supportsApiFormat = routeSupportsApiFormatSelection(capabilityRouteId)
  const supportsAuthHeaders = routeSupportsAuthHeaders(capabilityRouteId)
  const customHeaders = routeSupportsCustomHeaders(capabilityRouteId)
    ? sanitizeProfileCustomHeaders(profile.customHeaders)
    : undefined

  if (!id || !name || !baseUrl || !model || !provider) {
    return null
  }

  const maxContextLength =
    typeof profile.maxContextLength === 'number' &&
    Number.isFinite(profile.maxContextLength) &&
    profile.maxContextLength > 0 &&
    Number.isInteger(profile.maxContextLength)
      ? profile.maxContextLength
      : undefined

  const sanitized: ProviderProfile = {
    id,
    name,
    provider,
    baseUrl,
    model,
    apiKey: trimOrUndefined(profile.apiKey),
  }
  if (supportsApiFormat && apiFormat) {
    sanitized.apiFormat = apiFormat
  }
  if (supportsAuthHeaders && authHeader) {
    sanitized.authHeader = authHeader
    sanitized.authScheme = authScheme ?? (
      authHeader.toLowerCase() === 'authorization' ? 'bearer' : 'raw'
    )
    sanitized.authHeaderValue = authHeaderValue
  }
  if (customHeaders) {
    sanitized.customHeaders = customHeaders
  }
  if (maxContextLength !== undefined) {
    sanitized.maxContextLength = maxContextLength
  }
  return sanitized
}

function sanitizeProfiles(profiles: ProviderProfile[] | undefined): ProviderProfile[] {
  const seen = new Set<string>()
  const sanitized: ProviderProfile[] = []

  for (const profile of profiles ?? []) {
    const normalized = sanitizeProfile(profile)
    if (!normalized || seen.has(normalized.id)) {
      continue
    }
    seen.add(normalized.id)
    sanitized.push(normalized)
  }

  return sanitized
}

function nextProfileId(): string {
  return `provider_${randomBytes(6).toString('hex')}`
}

function toProfile(
  input: ProviderProfileInput,
  id: string = nextProfileId(),
): ProviderProfile | null {
  return sanitizeProfile({
    id,
    provider: input.provider ?? 'openai',
    name: input.name,
    baseUrl: input.baseUrl,
    model: input.model,
    apiKey: input.apiKey,
    apiFormat: input.apiFormat,
    authHeader: input.authHeader,
    authScheme: input.authScheme,
    authHeaderValue: input.authHeaderValue,
    customHeaders: input.customHeaders,
    maxContextLength: input.maxContextLength,
  })
}

function getSupportedProfileCustomHeadersEnv(
  profile: ProviderProfile,
): string | undefined {
  const routeId = resolveProfileCapabilityRouteId(
    profile.provider,
    profile.baseUrl,
  )
  if (!routeSupportsCustomHeaders(routeId)) {
    return undefined
  }
  return serializeProfileCustomHeaders(
    sanitizeProfileCustomHeaders(profile.customHeaders),
  )
}

function applySupportedProfileCustomHeaders(
  profile: ProviderProfile,
  env: ProfileEnv,
): ProfileEnv {
  const customHeaders = getSupportedProfileCustomHeadersEnv(profile)
  return customHeaders ? { ...env, ANTHROPIC_CUSTOM_HEADERS: customHeaders } : env
}

function getModelCacheByProfile(
  profileId: string,
  config = getGlobalConfig(),
): ModelOption[] {
  return config.openaiAdditionalModelOptionsCacheByProfile?.[profileId] ?? []
}

function mergeModelOptionsByValue(
  primaryOptions: ModelOption[],
  additionalOptions: ModelOption[],
): ModelOption[] {
  const merged: ModelOption[] = []
  const seen = new Set<string>()

  for (const option of [...primaryOptions, ...additionalOptions]) {
    if (typeof option.value !== 'string') {
      continue
    }
    const value = option.value.trim()
    if (!value || seen.has(value)) {
      continue
    }
    seen.add(value)
    merged.push({
      ...option,
      value,
    })
  }

  return merged
}

export function getProviderPresetDefaults(
  preset: ProviderPreset,
): ProviderPresetDefaults {
  const metadata = getProviderPresetUiMetadata(preset)
  // Keep preset-pinned endpoints/models even when generic OpenAI env values
  // are present, but still read provider-specific credential env vars above.
  const routeDefaults =
    preset === 'custom'
      ? metadata
      : getProviderPresetUiMetadata(preset, {})
  return {
    provider: metadata.provider,
    name: metadata.name,
    baseUrl: routeDefaults.baseUrl,
    model: routeDefaults.model,
    apiKey: metadata.apiKey,
    requiresApiKey: metadata.requiresApiKey,
  }
}

export function getProviderProfiles(
  config = getGlobalConfig(),
): ProviderProfile[] {
  return sanitizeProfiles(config.providerProfiles)
}

export function hasProviderProfiles(config = getGlobalConfig()): boolean {
  return getProviderProfiles(config).length > 0
}

function hasProviderSelectionFlags(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  return (
    processEnv.CLAUDE_CODE_USE_OPENAI !== undefined ||
    processEnv.CLAUDE_CODE_USE_GEMINI !== undefined ||
    processEnv.CLAUDE_CODE_USE_MISTRAL !== undefined ||
    processEnv.CLAUDE_CODE_USE_GITHUB !== undefined ||
    processEnv.CLAUDE_CODE_USE_BEDROCK !== undefined ||
    processEnv.CLAUDE_CODE_USE_VERTEX !== undefined ||
    processEnv.CLAUDE_CODE_USE_FOUNDRY !== undefined
  )
}

/**
 * A "complete" explicit provider selection = a USE flag AND at least one
 * concrete config value that tells us WHERE to route (a base URL) or WHAT
 * to run (a model id). A bare `CLAUDE_CODE_USE_OPENAI=1` with nothing else
 * is almost always a stale shell export from a previous session, not real
 * intent — and if we respect it, we skip the user's saved active profile
 * and fall back to hardcoded defaults (gpt-4o / api.openai.com), which is
 * the exact bug users report as "my saved provider isn't picked up".
 *
 * Used to gate whether saved-profile env should override shell state at
 * startup. The weaker `hasProviderSelectionFlags` is still used for the
 * anthropic-profile conflict check (any flag is a conflict for
 * first-party anthropic) and for alignment fingerprinting.
 */
function hasCompleteProviderSelection(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  if (resolveEnvOnlyProviderRouteId(processEnv) !== null) return true
  if (!hasProviderSelectionFlags(processEnv)) return false
  if (processEnv.CLAUDE_CODE_USE_OPENAI !== undefined) {
    return (
      trimOrUndefined(processEnv.OPENAI_BASE_URL) !== undefined ||
      trimOrUndefined(processEnv.OPENAI_API_BASE) !== undefined ||
      trimOrUndefined(processEnv.OPENAI_MODEL) !== undefined
    )
  }
  if (processEnv.CLAUDE_CODE_USE_GEMINI !== undefined) {
    return (
      trimOrUndefined(processEnv.GEMINI_BASE_URL) !== undefined ||
      trimOrUndefined(processEnv.GEMINI_MODEL) !== undefined ||
      trimOrUndefined(processEnv.GEMINI_API_KEY) !== undefined ||
      trimOrUndefined(processEnv.GOOGLE_API_KEY) !== undefined
    )
  }
  if (processEnv.CLAUDE_CODE_USE_MISTRAL !== undefined) {
    return (
      trimOrUndefined(processEnv.MISTRAL_BASE_URL) !== undefined ||
      trimOrUndefined(processEnv.MISTRAL_MODEL) !== undefined ||
      trimOrUndefined(processEnv.MISTRAL_API_KEY) !== undefined
    )
  }
  if (processEnv.CLAUDE_CODE_USE_GITHUB !== undefined) {
    return (
      trimOrUndefined(processEnv.GITHUB_ENTERPRISE_URL) !== undefined ||
      trimOrUndefined(processEnv.GITHUB_COPILOT_KEY) !== undefined ||
      trimOrUndefined(processEnv.GITHUB_TOKEN) !== undefined ||
      trimOrUndefined(processEnv.GH_TOKEN) !== undefined ||
      trimOrUndefined(processEnv.OPENAI_MODEL) !== undefined
    )
  }
  // Bedrock / Vertex / Foundry signal cloud-provider routing in env; treat
  // the flag alone as complete (these paths rely on ambient AWS/GCP creds).
  return true
}

function hasConflictingProviderFlagsForProfile(
  processEnv: NodeJS.ProcessEnv,
  profile: ProviderProfile,
): boolean {
  const { compatibilityMode } = resolveProfileCompatibility(profile.provider)

  if (compatibilityMode === 'anthropic') {
    return hasProviderSelectionFlags(processEnv)
  }

  return (
    (compatibilityMode !== 'openai' && processEnv.CLAUDE_CODE_USE_OPENAI !== undefined) ||
    (compatibilityMode !== 'gemini' && processEnv.CLAUDE_CODE_USE_GEMINI !== undefined) ||
    (compatibilityMode !== 'mistral' && processEnv.CLAUDE_CODE_USE_MISTRAL !== undefined) ||
    (!isGithubCompatibilityMode(compatibilityMode) &&
      processEnv.CLAUDE_CODE_USE_GITHUB !== undefined) ||
    (compatibilityMode !== 'bedrock' && processEnv.CLAUDE_CODE_USE_BEDROCK !== undefined) ||
    (compatibilityMode !== 'vertex' && processEnv.CLAUDE_CODE_USE_VERTEX !== undefined) ||
    processEnv.CLAUDE_CODE_USE_FOUNDRY !== undefined
  )
}

function sameOptionalEnvValue(
  left: string | undefined,
  right: string | undefined,
): boolean {
  return trimOrUndefined(left) === trimOrUndefined(right)
}

function isProcessEnvAlignedWithProfile(
  processEnv: NodeJS.ProcessEnv,
  profile: ProviderProfile,
  options?: {
    includeApiKey?: boolean
    primaryModel?: string
  },
): boolean {
  const includeApiKey = options?.includeApiKey ?? true
  const primaryModel = options?.primaryModel ?? getPrimaryModel(profile.model)
  const { compatibilityMode } = resolveProfileCompatibility(profile.provider)

  if (processEnv[PROFILE_ENV_APPLIED_FLAG] !== '1') {
    return false
  }

  if (trimOrUndefined(processEnv[PROFILE_ENV_APPLIED_ID]) !== profile.id) {
    return false
  }

  if (compatibilityMode === 'anthropic') {
    return (
      !hasProviderSelectionFlags(processEnv) &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_BASE_URL, profile.baseUrl) &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_MODEL, primaryModel) &&
      (!includeApiKey ||
        sameOptionalEnvValue(processEnv.ANTHROPIC_API_KEY, profile.apiKey))
    )
  }

  if (compatibilityMode === 'mistral') {
    return (
      processEnv.CLAUDE_CODE_USE_MISTRAL !== undefined &&
      processEnv.CLAUDE_CODE_USE_GEMINI === undefined &&
      processEnv.CLAUDE_CODE_USE_OPENAI === undefined &&
      processEnv.CLAUDE_CODE_USE_GITHUB === undefined &&
      processEnv.CLAUDE_CODE_USE_BEDROCK === undefined &&
      processEnv.CLAUDE_CODE_USE_VERTEX === undefined &&
      processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
      sameOptionalEnvValue(processEnv.MISTRAL_BASE_URL, profile.baseUrl) &&
      sameOptionalEnvValue(processEnv.MISTRAL_MODEL, primaryModel) &&
      (!includeApiKey ||
        sameOptionalEnvValue(processEnv.MISTRAL_API_KEY, profile.apiKey))
    )
  }

  if (compatibilityMode === 'gemini') {
    return (
      processEnv.CLAUDE_CODE_USE_GEMINI !== undefined &&
      processEnv.CLAUDE_CODE_USE_MISTRAL === undefined &&
      processEnv.CLAUDE_CODE_USE_OPENAI === undefined &&
      processEnv.CLAUDE_CODE_USE_GITHUB === undefined &&
      processEnv.CLAUDE_CODE_USE_BEDROCK === undefined &&
      processEnv.CLAUDE_CODE_USE_VERTEX === undefined &&
      processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
      sameOptionalEnvValue(processEnv.GEMINI_BASE_URL, profile.baseUrl) &&
      sameOptionalEnvValue(processEnv.GEMINI_MODEL, primaryModel) &&
      (!includeApiKey ||
        sameOptionalEnvValue(processEnv.GEMINI_API_KEY, profile.apiKey))
    )
  }

  if (isGithubCompatibilityMode(compatibilityMode)) {
    const expectedGheUrl =
      profile.provider === 'github-enterprise'
        ? deriveGithubEnterpriseUrl(profile.baseUrl)
        : undefined
    return (
      processEnv.CLAUDE_CODE_USE_GITHUB !== undefined &&
      processEnv.CLAUDE_CODE_USE_OPENAI === undefined &&
      processEnv.CLAUDE_CODE_USE_GEMINI === undefined &&
      processEnv.CLAUDE_CODE_USE_MISTRAL === undefined &&
      processEnv.CLAUDE_CODE_USE_BEDROCK === undefined &&
      processEnv.CLAUDE_CODE_USE_VERTEX === undefined &&
      processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
      sameOptionalEnvValue(processEnv.OPENAI_BASE_URL, profile.baseUrl) &&
      sameOptionalEnvValue(processEnv.OPENAI_MODEL, primaryModel) &&
      sameOptionalEnvValue(processEnv.GITHUB_ENTERPRISE_URL, expectedGheUrl) &&
      (profile.provider !== 'github-enterprise' ||
        !includeApiKey ||
        sameOptionalEnvValue(processEnv.GITHUB_COPILOT_KEY, profile.apiKey))
    )
  }

  if (compatibilityMode === 'bedrock') {
    return (
      processEnv.CLAUDE_CODE_USE_BEDROCK !== undefined &&
      processEnv.CLAUDE_CODE_USE_OPENAI === undefined &&
      processEnv.CLAUDE_CODE_USE_GEMINI === undefined &&
      processEnv.CLAUDE_CODE_USE_MISTRAL === undefined &&
      processEnv.CLAUDE_CODE_USE_GITHUB === undefined &&
      processEnv.CLAUDE_CODE_USE_VERTEX === undefined &&
      processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_MODEL, primaryModel) &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_BEDROCK_BASE_URL, profile.baseUrl)
    )
  }

  if (compatibilityMode === 'vertex') {
    return (
      processEnv.CLAUDE_CODE_USE_VERTEX !== undefined &&
      processEnv.CLAUDE_CODE_USE_OPENAI === undefined &&
      processEnv.CLAUDE_CODE_USE_GEMINI === undefined &&
      processEnv.CLAUDE_CODE_USE_MISTRAL === undefined &&
      processEnv.CLAUDE_CODE_USE_GITHUB === undefined &&
      processEnv.CLAUDE_CODE_USE_BEDROCK === undefined &&
      processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_MODEL, primaryModel) &&
      sameOptionalEnvValue(processEnv.ANTHROPIC_VERTEX_BASE_URL, profile.baseUrl)
    )
  }

  const expectedContextWindows = profile.maxContextLength
    ? JSON.stringify({
        [primaryModel]: profile.maxContextLength,
      })
    : undefined

  return (
    processEnv.CLAUDE_CODE_USE_OPENAI !== undefined &&
    processEnv.CLAUDE_CODE_USE_GEMINI === undefined &&
    processEnv.CLAUDE_CODE_USE_MISTRAL === undefined &&
    processEnv.CLAUDE_CODE_USE_GITHUB === undefined &&
    processEnv.CLAUDE_CODE_USE_BEDROCK === undefined &&
    processEnv.CLAUDE_CODE_USE_VERTEX === undefined &&
    processEnv.CLAUDE_CODE_USE_FOUNDRY === undefined &&
    sameOptionalEnvValue(processEnv.OPENAI_BASE_URL, profile.baseUrl) &&
    sameOptionalEnvValue(processEnv.OPENAI_MODEL, primaryModel) &&
    sameOptionalEnvValue(processEnv.OPENAI_API_FORMAT, profile.apiFormat) &&
    sameOptionalEnvValue(processEnv.OPENAI_AUTH_HEADER, profile.authHeader) &&
    sameOptionalEnvValue(processEnv.OPENAI_AUTH_SCHEME, profile.authScheme) &&
    sameOptionalEnvValue(processEnv.OPENAI_AUTH_HEADER_VALUE, profile.authHeaderValue) &&
    sameOptionalEnvValue(
      processEnv.CLAUDE_CODE_OPENAI_CONTEXT_WINDOWS,
      expectedContextWindows,
    ) &&
    (!includeApiKey ||
      sameOptionalEnvValue(processEnv.OPENAI_API_KEY, profile.apiKey)) &&
    (profile.baseUrl?.toLowerCase().includes('bankr')
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.BNKR_API_KEY, profile.apiKey)
      : true) &&
    (isXaiBaseUrl(profile.baseUrl)
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.XAI_API_KEY, profile.apiKey)
      : true) &&
    (profile.baseUrl?.toLowerCase().includes('api.venice.ai')
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.VENICE_API_KEY, profile.apiKey)
      : true) &&
    (profile.baseUrl?.toLowerCase().includes('api.xiaomimimo.com') ||
      profile.baseUrl?.toLowerCase().includes('api.mimo-v2.com')
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.MIMO_API_KEY, profile.apiKey)
      : true) &&
    (profile.baseUrl?.toLowerCase().includes('atlascloud')
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.ATLAS_CLOUD_API_KEY, profile.apiKey)
      : true) &&
    (isNearaiBaseUrl(profile.baseUrl)
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.NEARAI_API_KEY, profile.apiKey)
      : true) &&
    (isFireworksBaseUrl(profile.baseUrl)
      ? !includeApiKey ||
        sameOptionalEnvValue(processEnv.FIREWORKS_API_KEY, profile.apiKey)
      : true)
  )
}

export function getActiveProviderProfile(
  config = getGlobalConfig(),
): ProviderProfile | undefined {
  const profiles = getProviderProfiles(config)
  if (profiles.length === 0) {
    return undefined
  }

  const activeId = trimOrUndefined(config.activeProviderProfileId)
  return profiles.find(profile => profile.id === activeId) ?? profiles[0]
}

export function clearProviderProfileEnvFromProcessEnv(
  processEnv: NodeJS.ProcessEnv = process.env,
): void {
  clearManagedProfileEnv(processEnv)
  delete processEnv[PROFILE_ENV_APPLIED_FLAG]
  delete processEnv[PROFILE_ENV_APPLIED_ID]
}

export function applyProviderProfileToProcessEnv(
  profile: ProviderProfile,
  options?: { primaryModel?: string },
): void {
  const { route, compatibilityMode } = resolveProfileCompatibility(profile.provider)
  const primaryModel = options?.primaryModel ?? getPrimaryModel(profile.model)
  let profileEnv: ProfileEnv

  if (route.routeId === 'unknown-fallback') {
    // Safe fallback for unrecognised providers — OpenAI-compatible so the
    // user can still interact, but warn that the provider string was not
    // resolved to a known descriptor.
    console.warn(
      `[applyProviderProfileToProcessEnv] Unknown provider "${profile.provider}" — falling back to OpenAI-compatible env shaping.`,
    )
  }

  if (compatibilityMode === 'anthropic') {
    if (route.vendorId === 'minimax') {
      profileEnv =
        buildMiniMaxProfileEnv({
          model: primaryModel,
          baseUrl: profile.baseUrl,
          apiKey: profile.apiKey,
          processEnv: process.env,
        }) ?? {}
    } else {
      profileEnv = {
        ANTHROPIC_BASE_URL: profile.baseUrl,
        ANTHROPIC_MODEL: primaryModel,
        ...(profile.apiKey ? { ANTHROPIC_API_KEY: profile.apiKey } : {}),
      }
    }
  } else if (compatibilityMode === 'mistral') {
    profileEnv = {
      MISTRAL_BASE_URL: profile.baseUrl,
      MISTRAL_MODEL: primaryModel,
      ...(profile.apiKey ? { MISTRAL_API_KEY: profile.apiKey } : {}),
    }
  } else if (compatibilityMode === 'gemini') {
    profileEnv = {
      GEMINI_BASE_URL: profile.baseUrl,
      GEMINI_MODEL: primaryModel,
      ...(profile.apiKey ? { GEMINI_API_KEY: profile.apiKey } : {}),
    }
  } else if (isGithubCompatibilityMode(compatibilityMode)) {
    profileEnv = buildGithubCompatibleProfileEnv({
      model: primaryModel,
      baseUrl: profile.baseUrl,
      gatewayId:
        profile.provider === 'github-enterprise'
          ? 'github-enterprise'
          : route.gatewayId,
      apiKey: profile.apiKey,
    })
  } else if (compatibilityMode === 'bedrock') {
    profileEnv = buildBedrockProfileEnv({
      model: primaryModel,
      baseUrl: profile.baseUrl,
    })
  } else if (compatibilityMode === 'vertex') {
    profileEnv = buildVertexProfileEnv({
      model: primaryModel,
      baseUrl: profile.baseUrl,
    })
  } else {
    const capabilityRouteId = resolveProfileCapabilityRouteId(
      profile.provider,
      profile.baseUrl,
    )
    const supportsApiFormat = routeSupportsApiFormatSelection(capabilityRouteId)
    const supportsAuthHeaders = routeSupportsAuthHeaders(capabilityRouteId)
    const normalizedProfileBaseUrl =
      route.routeId === 'xiaomi-mimo' || route.routeId === 'xiaomi-mimo-token'
        ? normalizeXiaomiMimoBaseUrl(profile.baseUrl) ?? profile.baseUrl
        : profile.baseUrl
    const openAIProfileEnv: ProfileEnv = {
      OPENAI_BASE_URL: normalizedProfileBaseUrl,
      OPENAI_MODEL: primaryModel,
    }
    if (supportsApiFormat && profile.apiFormat) {
      openAIProfileEnv.OPENAI_API_FORMAT = profile.apiFormat
    }
    if (supportsAuthHeaders && profile.authHeader) {
      openAIProfileEnv.OPENAI_AUTH_HEADER = profile.authHeader
      openAIProfileEnv.OPENAI_AUTH_SCHEME =
        profile.authScheme ??
        (profile.authHeader.toLowerCase() === 'authorization'
          ? 'bearer'
          : 'raw')
      if (profile.authHeaderValue) {
        openAIProfileEnv.OPENAI_AUTH_HEADER_VALUE = profile.authHeaderValue
      }
    }

    if (profile.apiKey) {
      openAIProfileEnv.OPENAI_API_KEY = profile.apiKey
      if (route.vendorId === 'minimax' || profile.baseUrl.toLowerCase().includes('minimax')) {
        openAIProfileEnv.MINIMAX_API_KEY = profile.apiKey
      }
      if (
        route.gatewayId === 'nvidia-nim' ||
        profile.baseUrl.toLowerCase().includes('nvidia') ||
        profile.baseUrl.toLowerCase().includes('integrate.api.nvidia')
      ) {
        openAIProfileEnv.NVIDIA_API_KEY = profile.apiKey
      }
      if (route.routeId === 'bankr' || profile.baseUrl.toLowerCase().includes('bankr')) {
        openAIProfileEnv.BNKR_API_KEY = profile.apiKey
      }
      if (route.routeId === 'xai' || isXaiBaseUrl(profile.baseUrl)) {
        openAIProfileEnv.XAI_API_KEY = profile.apiKey
      }
      if (route.routeId === 'venice' || profile.baseUrl.toLowerCase().includes('api.venice.ai')) {
        openAIProfileEnv.VENICE_API_KEY = profile.apiKey
      }
      if (
        route.routeId === 'xiaomi-mimo' ||
        route.routeId === 'xiaomi-mimo-token' ||
        isXiaomiMimoBaseUrl(profile.baseUrl)
      ) {
        openAIProfileEnv.MIMO_API_KEY = profile.apiKey
      }
      if (route.routeId === 'atlas-cloud' || profile.baseUrl.toLowerCase().includes('atlascloud')) {
        openAIProfileEnv.ATLAS_CLOUD_API_KEY = profile.apiKey
      }
      if (route.routeId === 'nearai' || isNearaiBaseUrl(profile.baseUrl)) {
        openAIProfileEnv.NEARAI_API_KEY = profile.apiKey
      }
      if (route.routeId === 'fireworks' || isFireworksBaseUrl(profile.baseUrl)) {
        openAIProfileEnv.FIREWORKS_API_KEY = profile.apiKey
      }
    }
    if (route.gatewayId === 'nvidia-nim') {
      openAIProfileEnv.NVIDIA_NIM = '1'
    }
    if (profile.maxContextLength) {
      openAIProfileEnv.CLAUDE_CODE_OPENAI_CONTEXT_WINDOWS = JSON.stringify({
        [primaryModel]: profile.maxContextLength,
      })
    }

    profileEnv = openAIProfileEnv
  }

  profileEnv = applySupportedProfileCustomHeaders(profile, profileEnv)

  const nextEnv = buildCompatibilityProcessEnv({
    processEnv: process.env,
    compatibilityMode,
    profileEnv,
  })

  clearProviderProfileEnvFromProcessEnv()
  Object.assign(process.env, nextEnv)
  process.env[PROFILE_ENV_APPLIED_FLAG] = '1'
  process.env[PROFILE_ENV_APPLIED_ID] = profile.id
}

export function applyActiveProviderProfileFromConfig(
  config = getGlobalConfig(),
  options?: {
    processEnv?: NodeJS.ProcessEnv
    force?: boolean
  },
): ProviderProfile | undefined {
  const processEnv = options?.processEnv ?? process.env
  const activeProfile = getActiveProviderProfile(config)
  if (!activeProfile) {
    return undefined
  }

  const isCurrentEnvProfileManaged =
    processEnv[PROFILE_ENV_APPLIED_FLAG] === '1' &&
    trimOrUndefined(processEnv[PROFILE_ENV_APPLIED_ID]) === activeProfile.id

  if (!options?.force && (hasCompleteProviderSelection(processEnv) || processEnv[PROFILE_ENV_APPLIED_FLAG] === '1')) {
    // Respect explicit startup provider intent. Auto-heal only when this
    // exact active profile previously applied the current env.
    // NOTE: we gate on hasCompleteProviderSelection (flag + concrete config)
    // rather than hasProviderSelectionFlags alone. A bare CLAUDE_CODE_USE_*=1
    // with no BASE_URL/MODEL is almost always a stale shell export, not
    // intent — respecting it would skip the saved profile and fall through
    // to hardcoded provider defaults, which surfaces as "my saved provider
    // isn't being picked up at startup".
    if (!isCurrentEnvProfileManaged) {
      return undefined
    }

    if (hasConflictingProviderFlagsForProfile(processEnv, activeProfile)) {
      return undefined
    }

    const savedPrimaryModel = getSavedModelOverrideForProfile(activeProfile)
    if (
      isProcessEnvAlignedWithProfile(processEnv, activeProfile, {
        primaryModel: savedPrimaryModel,
      })
    ) {
      return activeProfile
    }
  }

  const savedPrimaryModel = getSavedModelOverrideForProfile(activeProfile)
  applyProviderProfileToProcessEnv(activeProfile, {
    primaryModel: savedPrimaryModel,
  })
  return activeProfile
}

export function addProviderProfile(
  input: ProviderProfileInput,
  options?: { makeActive?: boolean },
): ProviderProfile | null {
  const profile = toProfile(input)
  if (!profile) {
    return null
  }

  const makeActive = options?.makeActive ?? true

  saveGlobalConfig(current => {
    const currentProfiles = getProviderProfiles(current)
    const nextProfiles = [...currentProfiles, profile]
    const currentActive = trimOrUndefined(current.activeProviderProfileId)
    const nextActiveId =
      makeActive || !currentActive || !nextProfiles.some(p => p.id === currentActive)
        ? profile.id
        : currentActive

    return {
      ...current,
      providerProfiles: nextProfiles,
      activeProviderProfileId: nextActiveId,
    }
  })

  const activeProfile = getActiveProviderProfile()
  if (activeProfile?.id === profile.id) {
    setActiveProviderProfile(profile.id)
    clearActiveOpenAIModelOptionsCache()
  }

  return profile
}

export function updateProviderProfile(
  profileId: string,
  input: ProviderProfileInput,
): ProviderProfile | null {
  const updatedProfile = toProfile(input, profileId)
  if (!updatedProfile) {
    return null
  }

  let wasUpdated = false
  let shouldApply = false

  saveGlobalConfig(current => {
    const currentProfiles = getProviderProfiles(current)
    const profileIndex = currentProfiles.findIndex(
      profile => profile.id === profileId,
    )

    if (profileIndex < 0) {
      return current
    }

    wasUpdated = true

    const nextProfiles = [...currentProfiles]
    nextProfiles[profileIndex] = updatedProfile

    const cacheByProfile = {
      ...(current.openaiAdditionalModelOptionsCacheByProfile ?? {}),
    }
    delete cacheByProfile[profileId]

    const currentActive = trimOrUndefined(current.activeProviderProfileId)
    const nextActiveId =
      currentActive && nextProfiles.some(profile => profile.id === currentActive)
        ? currentActive
        : nextProfiles[0]?.id

    shouldApply = nextActiveId === profileId

    return {
      ...current,
      providerProfiles: nextProfiles,
      activeProviderProfileId: nextActiveId,
      openaiAdditionalModelOptionsCacheByProfile: cacheByProfile,
      openaiAdditionalModelOptionsCache: shouldApply
        ? []
        : current.openaiAdditionalModelOptionsCache,
    }
  })

  if (!wasUpdated) {
    return null
  }

  if (shouldApply) {
    applyProviderProfileToProcessEnv(updatedProfile)
  }

  return updatedProfile
}

export function persistActiveProviderProfileModel(
  model: string,
): ProviderProfile | null {
  const nextModel = trimOrUndefined(model)
  if (!nextModel) {
    return null
  }

  const activeProfile = getActiveProviderProfile()
  if (!activeProfile) {
    return null
  }

  // Runtime model selection is a session-level choice handled by
  // mainLoopModelOverride (see src/hooks/useMainLoopModel.ts), not a
  // profile edit. Whether the chosen model is already part of the
  // profile's list or not, do NOT mutate profile.model here:
  //   - if it IS in the list, the list is already correct (no-op)
  //   - if it ISN'T, the user picked an out-of-list model for the
  //     session and the profile's list should only change via an
  //     explicit provider edit, not by side-effect of /model.
  // An earlier implementation prepended out-of-list models to the
  // profile, which (a) contradicted this contract, (b) caused
  // unbounded list growth on rotation, and (c) used a separator
  // inferred from a single-character substring of the model field
  // that broke on mixed-separator inputs.
  return activeProfile
}

export function getConfiguredProfileModelOptions(
  profile: ProviderProfile,
): ModelOption[] {
  return parseModelList(profile.model).map(model => ({
    value: model,
    label: model,
    description: `Provider: ${profile.name}`,
  }))
}

/**
 * Generate model options from a provider profile's model field.
 * Each parsed model becomes a separate option in the picker, then any
 * discovered OpenAI-compatible models cached for the same profile are
 * appended without duplicates.
 */
export function getProfileModelOptions(
  profile: ProviderProfile,
  config = getGlobalConfig(),
): ModelOption[] {
  const configuredOptions = getConfiguredProfileModelOptions(profile)
  return mergeModelOptionsByValue(
    configuredOptions,
    getModelCacheByProfile(profile.id, config),
  )
}

function buildOpenAICompatibleStartupEnv(
  activeProfile: ProviderProfile,
): ProfileEnv | null {
  if (isCodexBaseUrl(activeProfile.baseUrl)) {
    return null
  }

  if (activeProfile.apiKey) {
    const strictEnv = buildOpenAIProfileEnv({
      goal: 'balanced',
      model: activeProfile.model,
      baseUrl: activeProfile.baseUrl,
      apiKey: activeProfile.apiKey,
      apiFormat: activeProfile.apiFormat,
      authHeader: activeProfile.authHeader,
      authScheme: activeProfile.authScheme,
      authHeaderValue: activeProfile.authHeaderValue,
      maxContextLength: activeProfile.maxContextLength,
      processEnv: {},
    })
    if (strictEnv) {
      // Atlas Cloud is dedicatedCredentialsOnly: its route ignores
      // OPENAI_API_KEY, so a generic OpenAI profile pointed at Atlas must
      // persist the dedicated key too or it relaunches unauthenticated.
      if (activeProfile.baseUrl?.toLowerCase().includes('atlascloud')) {
        strictEnv.ATLAS_CLOUD_API_KEY = activeProfile.apiKey
      }
      if (isNearaiBaseUrl(activeProfile.baseUrl)) {
        strictEnv.NEARAI_API_KEY = activeProfile.apiKey
      }
      if (isFireworksBaseUrl(activeProfile.baseUrl)) {
        strictEnv.FIREWORKS_API_KEY = activeProfile.apiKey
      }
      return applySupportedProfileCustomHeaders(activeProfile, strictEnv)
    }
  }

  const env: ProfileEnv = {
    OPENAI_BASE_URL: activeProfile.baseUrl,
    OPENAI_MODEL: getPrimaryModel(activeProfile.model),
    ...(activeProfile.apiFormat ? { OPENAI_API_FORMAT: activeProfile.apiFormat } : {}),
    ...(activeProfile.authHeader ? { OPENAI_AUTH_HEADER: activeProfile.authHeader } : {}),
    ...(activeProfile.authScheme ? { OPENAI_AUTH_SCHEME: activeProfile.authScheme } : {}),
    ...(activeProfile.authHeaderValue ? { OPENAI_AUTH_HEADER_VALUE: activeProfile.authHeaderValue } : {}),
    ...(activeProfile.maxContextLength
      ? {
          CLAUDE_CODE_OPENAI_CONTEXT_WINDOWS: JSON.stringify({
            [getPrimaryModel(activeProfile.model)]: activeProfile.maxContextLength,
          }),
        }
      : {}),
  }

  if (activeProfile.apiKey) {
    env.OPENAI_API_KEY = activeProfile.apiKey
    if (activeProfile.baseUrl?.toLowerCase().includes('bankr')) {
      env.BNKR_API_KEY = activeProfile.apiKey
    }
    if (isXaiBaseUrl(activeProfile.baseUrl)) {
      env.XAI_API_KEY = activeProfile.apiKey
    }
    if (activeProfile.baseUrl?.toLowerCase().includes('api.venice.ai')) {
      env.VENICE_API_KEY = activeProfile.apiKey
    }
    if (
      activeProfile.baseUrl?.toLowerCase().includes('api.xiaomimimo.com') ||
      activeProfile.baseUrl?.toLowerCase().includes('api.mimo-v2.com')
    ) {
      env.MIMO_API_KEY = activeProfile.apiKey
    }
    if (activeProfile.baseUrl?.toLowerCase().includes('atlascloud')) {
      env.ATLAS_CLOUD_API_KEY = activeProfile.apiKey
    }
    if (isNearaiBaseUrl(activeProfile.baseUrl)) {
      env.NEARAI_API_KEY = activeProfile.apiKey
    }
    if (isFireworksBaseUrl(activeProfile.baseUrl)) {
      env.FIREWORKS_API_KEY = activeProfile.apiKey
    }
  } else {
    delete env.OPENAI_API_KEY
  }
  return applySupportedProfileCustomHeaders(activeProfile, env)
}

function buildStartupProfileFromActiveProfile(
  activeProfile: ProviderProfile,
): {
  profile: ProviderProfileStartup
  env: ProfileEnv
} | null {
  const { route, compatibilityMode } = resolveProfileCompatibility(activeProfile.provider)

  switch (compatibilityMode) {
    case 'anthropic':
      if (route.vendorId === 'minimax') {
        const env =
          buildMiniMaxProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'minimax', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }
      return {
        profile: 'anthropic',
        env: applySupportedProfileCustomHeaders(activeProfile, {
          ANTHROPIC_BASE_URL: activeProfile.baseUrl,
          ANTHROPIC_MODEL: getPrimaryModel(activeProfile.model),
          ...(activeProfile.apiKey
            ? { ANTHROPIC_API_KEY: activeProfile.apiKey }
            : {}),
        }),
      }
    case 'gemini': {
      const env =
        buildGeminiProfileEnv({
          model: getPrimaryModel(activeProfile.model),
          baseUrl: activeProfile.baseUrl,
          apiKey: activeProfile.apiKey,
          authMode: 'api-key',
          processEnv: process.env,
        }) ?? null
      return env
        ? { profile: 'gemini', env: applySupportedProfileCustomHeaders(activeProfile, env) }
        : null
    }
    case 'mistral': {
      const env =
        buildMistralProfileEnv({
          model: getPrimaryModel(activeProfile.model),
          baseUrl: activeProfile.baseUrl,
          apiKey: activeProfile.apiKey,
          processEnv: process.env,
        }) ?? null
      return env
        ? { profile: 'mistral', env: applySupportedProfileCustomHeaders(activeProfile, env) }
        : null
    }
    case 'github':
    case 'github-enterprise': {
      return {
        profile:
          activeProfile.provider === 'github-enterprise'
            ? 'github-enterprise'
            : 'github',
        env: applySupportedProfileCustomHeaders(
          activeProfile,
          buildGithubCompatibleProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            gatewayId:
              activeProfile.provider === 'github-enterprise'
                ? 'github-enterprise'
                : 'github',
          }),
        ),
      }
    }
    case 'bedrock':
      return {
        profile: 'bedrock',
        env: applySupportedProfileCustomHeaders(activeProfile, buildBedrockProfileEnv({
          model: getPrimaryModel(activeProfile.model),
          baseUrl: activeProfile.baseUrl,
        })),
      }
    case 'vertex':
      return {
        profile: 'vertex',
        env: applySupportedProfileCustomHeaders(activeProfile, buildVertexProfileEnv({
          model: getPrimaryModel(activeProfile.model),
          baseUrl: activeProfile.baseUrl,
        })),
      }
    case 'openai': {
      if (route.gatewayId === 'nvidia-nim') {
        const env =
          buildNvidiaNimProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'nvidia-nim', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }

      if (route.vendorId === 'minimax') {
        const env =
          buildMiniMaxProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'minimax', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }

      if (route.vendorId === 'venice') {
        const env =
          buildVeniceProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'openai', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }

      if (route.vendorId === 'xiaomi-mimo') {
        const env =
          buildXiaomiMimoProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'openai', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }

      if (route.routeId === 'atlas-cloud') {
        const env =
          buildAtlasCloudProfileEnv({
            model: getPrimaryModel(activeProfile.model),
            baseUrl: activeProfile.baseUrl,
            apiKey: activeProfile.apiKey,
            processEnv: process.env,
          }) ?? null
        return env
          ? { profile: 'openai', env: applySupportedProfileCustomHeaders(activeProfile, env) }
          : null
      }

      if (route.vendorId === 'nearai') {
        const env = buildOpenAICompatibleStartupEnv(activeProfile)
        return env ? { profile: 'openai', env } : null
      }

      // xAI OAuth profile (provider=xai with no API key). Tag the startup
      // file with profile='xai' + XAI_CREDENTIAL_SOURCE=oauth so:
      //   1. validation accepts it at startup (no spurious
      //      "XAI_API_KEY is required" before openaiShim resolves the
      //      stored OAuth token)
      //   2. `clearPersistedXaiOAuthProfile()` can identify and remove it
      //      on logout, instead of leaving a stale openai-shaped file
      //      pointing at api.x.ai with no credential.
      if (route.vendorId === 'xai' && !activeProfile.apiKey) {
        const env = applySupportedProfileCustomHeaders(activeProfile, {
          ...buildXaiOAuthProfileEnv({
            model: getPrimaryModel(activeProfile.model),
          }),
          OPENAI_BASE_URL: activeProfile.baseUrl,
        })
        return { profile: 'xai', env }
      }

      const env = buildOpenAICompatibleStartupEnv(activeProfile)
      return env ? { profile: 'openai', env } : null
    }
  }
}

function triggerStartupDiscoveryRefreshForProfile(
  profile: ProviderProfile,
): void {
  const route = resolveProfileRoute(profile.provider)
  if (route.routeId === 'unknown-fallback') {
    return
  }

  void refreshStartupDiscoveryForRoute(route.routeId, {
    baseUrl: profile.baseUrl,
    apiKey: profile.apiKey,
    headers: sanitizeProfileCustomHeaders(profile.customHeaders),
  }).catch(error => {
    const detail = error instanceof Error ? error.message : String(error)
    logForDebugging(
      `[providerProfiles] Startup discovery refresh failed for ${route.routeId}: ${detail}`,
    )
  })
}

export function setActiveProviderProfile(
  profileId: string,
  options?: ProfileFileLocation,
): ProviderProfile | null {
  const current = getGlobalConfig()
  const profiles = getProviderProfiles(current)
  const activeProfile = profiles.find(profile => profile.id === profileId)

  if (!activeProfile) {
    return null
  }

  const profileModelOptions = getProfileModelOptions(activeProfile, current)

  saveGlobalConfig(config => ({
    ...config,
    activeProviderProfileId: profileId,
    openaiAdditionalModelOptionsCache: profileModelOptions,
    openaiAdditionalModelOptionsCacheByProfile: {
      ...(config.openaiAdditionalModelOptionsCacheByProfile ?? {}),
      [profileId]: profileModelOptions,
    },
  }))

  applyProviderProfileToProcessEnv(activeProfile)
  triggerStartupDiscoveryRefreshForProfile(activeProfile)

  // Keep startup persisted provider profile in sync so initial startup
  // uses the selected provider/model.
  const startupProfile = buildStartupProfileFromActiveProfile(activeProfile)

  if (startupProfile) {
    const file = createProfileFile(startupProfile.profile, startupProfile.env)
    saveProfileFile(file, options)
  }

  return activeProfile
}

export function deleteProviderProfile(profileId: string): {
  removed: boolean
  activeProfileId?: string
} {
  let removed = false
  let deletedProfile: ProviderProfile | undefined
  let nextActiveProfile: ProviderProfile | undefined

  saveGlobalConfig(current => {
    const currentProfiles = getProviderProfiles(current)
    const existing = currentProfiles.find(profile => profile.id === profileId)

    if (!existing) {
      return current
    }

    removed = true
    deletedProfile = existing

    const nextProfiles = currentProfiles.filter(profile => profile.id !== profileId)
    const currentActive = trimOrUndefined(current.activeProviderProfileId)
    const activeWasDeleted =
      !currentActive || currentActive === profileId ||
      !nextProfiles.some(profile => profile.id === currentActive)

    const nextActiveId = activeWasDeleted ? nextProfiles[0]?.id : currentActive

    if (nextActiveId) {
      nextActiveProfile =
        nextProfiles.find(profile => profile.id === nextActiveId) ?? nextProfiles[0]
    }

    const cacheByProfile = {
      ...(current.openaiAdditionalModelOptionsCacheByProfile ?? {}),
    }
    delete cacheByProfile[profileId]

    return {
      ...current,
      providerProfiles: nextProfiles,
      activeProviderProfileId: nextActiveId,
      openaiAdditionalModelOptionsCacheByProfile: cacheByProfile,
      openaiAdditionalModelOptionsCache: nextActiveId
        ? (
            nextActiveProfile
              ? getProfileModelOptions(nextActiveProfile, {
                  ...current,
                  providerProfiles: nextProfiles,
                  activeProviderProfileId: nextActiveId,
                  openaiAdditionalModelOptionsCacheByProfile: cacheByProfile,
                })
              : []
          )
        : [],
    }
  })

  if (nextActiveProfile) {
    applyProviderProfileToProcessEnv(nextActiveProfile)
  } else if (
    deletedProfile &&
    isProcessEnvAlignedWithProfile(process.env, deletedProfile, {
      includeApiKey: false,
    })
  ) {
    clearProviderProfileEnvFromProcessEnv()
  }

  return {
    removed,
    activeProfileId: nextActiveProfile?.id,
  }
}

export function getActiveOpenAIModelOptionsCache(
  config = getGlobalConfig(),
): ModelOption[] {
  const activeProfile = getActiveProviderProfile(config)

  if (!activeProfile) {
    return config.openaiAdditionalModelOptionsCache ?? []
  }

  const cached = config.openaiAdditionalModelOptionsCacheByProfile?.[
    activeProfile.id
  ]
  if (cached) {
    return cached
  }

  const profileOptions = getProfileModelOptions(activeProfile, config)
  if (profileOptions.length > 0) {
    return profileOptions
  }

  // Backward compatibility for users who have only the legacy single cache.
  if (
    Object.keys(config.openaiAdditionalModelOptionsCacheByProfile ?? {}).length ===
    0
  ) {
    return config.openaiAdditionalModelOptionsCache ?? []
  }

  return []
}

export function setActiveOpenAIModelOptionsCache(options: ModelOption[]): void {
  const activeProfile = getActiveProviderProfile()

  if (!activeProfile) {
    saveGlobalConfig(current => ({
      ...current,
      openaiAdditionalModelOptionsCache: options,
    }))
    return
  }

  const mergedOptions = mergeModelOptionsByValue(
    parseModelList(activeProfile.model).map(model => ({
      value: model,
      label: model,
      description: `Provider: ${activeProfile.name}`,
    })),
    options,
  )

  saveGlobalConfig(current => ({
    ...current,
    openaiAdditionalModelOptionsCache: mergedOptions,
    openaiAdditionalModelOptionsCacheByProfile: {
      ...(current.openaiAdditionalModelOptionsCacheByProfile ?? {}),
      [activeProfile.id]: mergedOptions,
    },
  }))
}

export function getActiveOpenAIRouteModelOptionsCache(
  config = getGlobalConfig(),
): ModelOption[] {
  const activeScope = getAdditionalModelOptionsCacheScope()

  return activeScope?.startsWith('openai:') &&
    config.additionalModelOptionsCacheScope === activeScope
    ? (config.additionalModelOptionsCache ?? [])
    : []
}

export function setActiveOpenAIRouteModelOptionsCache(
  options: ModelOption[],
): void {
  const activeScope = getAdditionalModelOptionsCacheScope()
  if (!activeScope?.startsWith('openai:')) {
    return
  }

  saveGlobalConfig(current => ({
    ...current,
    additionalModelOptionsCache: options,
    additionalModelOptionsCacheScope: activeScope,
  }))
}

export function clearActiveOpenAIModelOptionsCache(): void {
  const activeProfile = getActiveProviderProfile()

  if (!activeProfile) {
    saveGlobalConfig(current => ({
      ...current,
      openaiAdditionalModelOptionsCache: [],
    }))
    return
  }

  saveGlobalConfig(current => {
    const cacheByProfile = {
      ...(current.openaiAdditionalModelOptionsCacheByProfile ?? {}),
    }
    delete cacheByProfile[activeProfile.id]

    return {
      ...current,
      openaiAdditionalModelOptionsCache: [],
      openaiAdditionalModelOptionsCacheByProfile: cacheByProfile,
    }
  })
}
