import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import {
  DEFAULT_CODEX_BASE_URL,
  DEFAULT_OPENAI_BASE_URL,
  isCodexBaseUrl,
  parseOpenAICompatibleApiFormat,
  resolveCodexApiCredentials,
  resolveProviderRequest,
} from '../services/api/providerConfig.js'
import { parseChatgptAccountId } from '../services/api/codexOAuthShared.js'
import {
  getGoalDefaultOpenAIModel,
  normalizeRecommendationGoal,
  type RecommendationGoal,
} from './providerRecommendation.js'
import { readGeminiAccessToken } from './geminiCredentials.js'
import { getOllamaChatBaseUrl } from './providerDiscovery.js'
import { getPrimaryModel } from './providerModels.js'
import { getProviderValidationError } from './providerValidation.js'
import { getErrnoCode } from './errors.js'
import {
  getRouteDefaultBaseUrl,
  getRouteDefaultModel,
  normalizeXiaomiMimoBaseUrl,
} from '../integrations/routeMetadata.js'
import {
  maskSecretForDisplay,
  redactSecretValueForDisplay,
  sanitizeApiKey,
  sanitizeProviderConfigValue,
} from './providerSecrets.js'

export {
  maskSecretForDisplay,
  redactSecretValueForDisplay,
  sanitizeApiKey,
  sanitizeProviderConfigValue,
} from './providerSecrets.js'
import { getClaudeConfigHomeDir, isEnvTruthy } from './envUtils.js'

export const PROFILE_FILE_NAME = '.openclaude-profile.json'
export const DEFAULT_GEMINI_BASE_URL =
  'https://generativelanguage.googleapis.com/v1beta/openai'
export const DEFAULT_GEMINI_MODEL = 'gemini-3-flash-preview'
export const DEFAULT_MISTRAL_BASE_URL = 'https://api.mistral.ai/v1'
export const DEFAULT_MISTRAL_MODEL = 'devstral-latest'

const PROFILE_ENV_KEYS = [
  'CLAUDE_CODE_USE_OPENAI',
  'CLAUDE_CODE_USE_GITHUB',
  'CLAUDE_CODE_USE_GEMINI',
  'CLAUDE_CODE_USE_MISTRAL',
  'CLAUDE_CODE_USE_BEDROCK',
  'CLAUDE_CODE_USE_VERTEX',
  'CLAUDE_CODE_USE_FOUNDRY',
  'ANTHROPIC_BASE_URL',
  'ANTHROPIC_MODEL',
  'ANTHROPIC_API_KEY',
  'ANTHROPIC_CUSTOM_HEADERS',
  'ANTHROPIC_BEDROCK_BASE_URL',
  'ANTHROPIC_VERTEX_BASE_URL',
  'OPENAI_BASE_URL',
  'OPENAI_API_BASE',
  'OPENAI_MODEL',
  'OPENAI_API_FORMAT',
  'OPENAI_AUTH_HEADER',
  'OPENAI_AUTH_SCHEME',
  'OPENAI_AUTH_HEADER_VALUE',
  'OPENAI_API_KEY',
  'CODEX_API_KEY',
  'CODEX_CREDENTIAL_SOURCE',
  'CHATGPT_ACCOUNT_ID',
  'CODEX_ACCOUNT_ID',
  'GEMINI_API_KEY',
  'GEMINI_AUTH_MODE',
  'GEMINI_ACCESS_TOKEN',
  'GEMINI_MODEL',
  'GEMINI_BASE_URL',
  'GOOGLE_API_KEY',
  'NVIDIA_NIM',
  'NVIDIA_API_KEY',
  'NVIDIA_MODEL',
  'MINIMAX_API_KEY',
  'MINIMAX_BASE_URL',
  'MINIMAX_MODEL',
  'MISTRAL_BASE_URL',
  'MISTRAL_API_KEY',
  'MISTRAL_MODEL',
  'BANKR_BASE_URL',
  'BNKR_API_KEY',
  'BANKR_MODEL',
  'XAI_API_KEY',
  'VENICE_API_KEY',
  'MIMO_API_KEY',
] as const

export type CompatibilityProfileMode =
  | 'anthropic'
  | 'openai'
  | 'gemini'
  | 'mistral'
  | 'github'
  | 'bedrock'
  | 'vertex'

const SECRET_ENV_KEYS = [
  'OPENAI_API_KEY',
  'OPENAI_AUTH_HEADER_VALUE',
  'CODEX_API_KEY',
  'GEMINI_API_KEY',
  'GOOGLE_API_KEY',
  'NVIDIA_API_KEY',
  'MINIMAX_API_KEY',
  'MISTRAL_API_KEY',
  'BNKR_API_KEY',
  'XAI_API_KEY',
  'VENICE_API_KEY',
  'MIMO_API_KEY',
] as const

export type ProviderProfile =
  | 'anthropic'
  | 'openai'
  | 'ollama'
  | 'codex'
  | 'gemini'
  | 'atomic-chat'
  | 'nvidia-nim'
  | 'minimax'
  | 'mistral'
  | 'github'
  | 'bedrock'
  | 'vertex'
  | 'xai'

export type ProfileEnv = {
  ANTHROPIC_BASE_URL?: string
  ANTHROPIC_MODEL?: string
  ANTHROPIC_API_KEY?: string
  ANTHROPIC_CUSTOM_HEADERS?: string
  ANTHROPIC_BEDROCK_BASE_URL?: string
  ANTHROPIC_VERTEX_BASE_URL?: string
  OPENAI_BASE_URL?: string
  OPENAI_API_BASE?: string
  OPENAI_MODEL?: string
  OPENAI_API_FORMAT?: 'chat_completions' | 'responses'
  OPENAI_AUTH_HEADER?: string
  OPENAI_AUTH_SCHEME?: 'bearer' | 'raw'
  OPENAI_AUTH_HEADER_VALUE?: string
  OPENAI_API_KEY?: string
  CODEX_API_KEY?: string
  CODEX_CREDENTIAL_SOURCE?: 'oauth' | 'existing'
  CHATGPT_ACCOUNT_ID?: string
  CODEX_ACCOUNT_ID?: string
  GEMINI_API_KEY?: string
  GEMINI_AUTH_MODE?: 'api-key' | 'access-token' | 'adc'
  GEMINI_ACCESS_TOKEN?: string
  GEMINI_MODEL?: string
  GEMINI_BASE_URL?: string
  GOOGLE_API_KEY?: string
  NVIDIA_NIM?: string
  NVIDIA_API_KEY?: string
  MINIMAX_API_KEY?: string
  MINIMAX_BASE_URL?: string
  MINIMAX_MODEL?: string
  MISTRAL_BASE_URL?: string
  MISTRAL_API_KEY?: string
  MISTRAL_MODEL?: string
  BANKR_BASE_URL?: string
  BNKR_API_KEY?: string
  BANKR_MODEL?: string
  XAI_API_KEY?: string
  VENICE_API_KEY?: string
  MIMO_API_KEY?: string
}

export type ProfileFile = {
  profile: ProviderProfile
  env: ProfileEnv
  createdAt: string
}

type SecretValueSource = Partial<
  Record<
    | 'OPENAI_API_KEY'
    | 'OPENAI_AUTH_HEADER_VALUE'
    | 'CODEX_API_KEY'
    | 'GEMINI_API_KEY'
    | 'GOOGLE_API_KEY'
    | 'NVIDIA_API_KEY'
    | 'MINIMAX_API_KEY'
    | 'MISTRAL_API_KEY'
    | 'BNKR_API_KEY'
    | 'XAI_API_KEY'
    | 'VENICE_API_KEY'
    | 'MIMO_API_KEY',
    string | undefined
  >
>

export type ProfileFileLocation = {
  configDir?: string
  cwd?: string
  filePath?: string
}

export function getDefaultProfileFilePath(configDir?: string): string {
  return join(configDir ?? getClaudeConfigHomeDir(), PROFILE_FILE_NAME)
}

function resolveLegacyProfileFilePath(cwd = process.cwd()): string {
  return resolve(cwd, PROFILE_FILE_NAME)
}

function resolveProfileFilePath(options?: ProfileFileLocation): string {
  if (options?.filePath) {
    return options.filePath
  }

  if (options?.cwd && !options?.configDir) {
    return resolveLegacyProfileFilePath(options.cwd)
  }

  return getDefaultProfileFilePath(options?.configDir)
}

function resolveProfileFileReadPaths(options?: ProfileFileLocation): string[] {
  const primary = resolveProfileFilePath(options)
  if (options?.filePath || (options?.cwd && !options?.configDir)) {
    return [primary]
  }

  if (existsSync(primary)) {
    return [primary]
  }

  const legacy = resolveLegacyProfileFilePath(options?.cwd)
  return legacy === primary ? [primary] : [primary, legacy]
}

function resolveProfileFileCleanupPaths(options?: ProfileFileLocation): string[] {
  const primary = resolveProfileFilePath(options)
  if (options?.filePath || (options?.cwd && !options?.configDir)) {
    return [primary]
  }

  const legacy = resolveLegacyProfileFilePath(options?.cwd)
  return legacy === primary ? [primary] : [primary, legacy]
}

function ensureProfileDirectory(filePath: string): void {
  try {
    mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 })
  } catch (error) {
    if (getErrnoCode(error) !== 'EEXIST') {
      throw error
    }
  }
}

function readProfileFile(filePath: string): ProfileFile | null {
  if (!existsSync(filePath)) {
    return null
  }

  try {
    const parsed = JSON.parse(readFileSync(filePath, 'utf8')) as Partial<ProfileFile>
    if (!isProviderProfile(parsed.profile) || !parsed.env || typeof parsed.env !== 'object') {
      return null
    }

    return {
      profile: parsed.profile,
      env: parsed.env,
      createdAt:
        typeof parsed.createdAt === 'string'
          ? parsed.createdAt
          : new Date().toISOString(),
    }
  } catch {
    return null
  }
}

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

  const primary = getPrimaryModel(trimmed)
  return primary.length > 0 ? primary : undefined
}

export function isProviderProfile(value: unknown): value is ProviderProfile {
  return (
    value === 'anthropic' ||
    value === 'openai' ||
    value === 'ollama' ||
    value === 'codex' ||
    value === 'gemini' ||
    value === 'atomic-chat' ||
    value === 'nvidia-nim' ||
    value === 'minimax' ||
    value === 'mistral' ||
    value === 'github' ||
    value === 'bedrock' ||
    value === 'vertex' ||
    value === 'xai'
  )
}

export function buildGithubProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
}): ProfileEnv {
  const env: ProfileEnv = {
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model),
      ) || 'github:copilot',
  }

  const baseUrl = sanitizeProviderConfigValue(options.baseUrl)
  if (baseUrl) {
    env.OPENAI_BASE_URL = baseUrl
  }

  return env
}

export function buildOllamaProfileEnv(
  model: string,
  options: {
    baseUrl?: string | null
    getOllamaChatBaseUrl: (baseUrl?: string) => string
  },
): ProfileEnv {
  return {
    OPENAI_BASE_URL: options.getOllamaChatBaseUrl(options.baseUrl ?? undefined),
    OPENAI_MODEL: model,
  }
}

export function buildAtomicChatProfileEnv(
  model: string,
  options: {
    baseUrl?: string | null
    getAtomicChatChatBaseUrl: (baseUrl?: string) => string
  },
): ProfileEnv {
  return {
    OPENAI_BASE_URL: options.getAtomicChatChatBaseUrl(options.baseUrl ?? undefined),
    OPENAI_MODEL: model,
  }
}

export function buildBedrockProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
}): ProfileEnv {
  const env: ProfileEnv = {
    ANTHROPIC_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model),
      ) || 'claude-sonnet-4-6',
  }

  const baseUrl = sanitizeProviderConfigValue(options.baseUrl)
  if (baseUrl) {
    env.ANTHROPIC_BEDROCK_BASE_URL = baseUrl
  }

  return env
}

export function buildVertexProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
}): ProfileEnv {
  const env: ProfileEnv = {
    ANTHROPIC_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model),
      ) || 'claude-sonnet-4-6',
  }

  const baseUrl = sanitizeProviderConfigValue(options.baseUrl)
  if (baseUrl) {
    env.ANTHROPIC_VERTEX_BASE_URL = baseUrl
  }

  return env
}

export function buildNvidiaNimProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.NVIDIA_API_KEY)
  if (!key) {
    return null
  }

  const defaultBaseUrl = 'https://integrate.api.nvidia.com/v1'
  const secretSource: SecretValueSource = { OPENAI_API_KEY: key }

  return {
    OPENAI_BASE_URL:
      sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
      sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL, secretSource) ||
      defaultBaseUrl,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL, secretSource),
      ) ||
      'nvidia/llama-3.1-nemotron-70b-instruct',
    OPENAI_API_KEY: key,
    NVIDIA_NIM: '1',
  }
}

export function buildMiniMaxProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.MINIMAX_API_KEY)
  if (!key) {
    return null
  }

  const defaultBaseUrl = getRouteDefaultBaseUrl('minimax')
  const defaultModel = getRouteDefaultModel('minimax')
  if (!defaultBaseUrl || !defaultModel) {
    throw new Error('MiniMax route defaults are missing from integration metadata.')
  }
  const secretSource: SecretValueSource = { OPENAI_API_KEY: key }

  return {
    OPENAI_BASE_URL:
      sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
      sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL, secretSource) ||
      defaultBaseUrl,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL, secretSource),
      ) ||
      defaultModel,
    OPENAI_API_KEY: key,
    MINIMAX_API_KEY: key,
    MINIMAX_BASE_URL: defaultBaseUrl,
    MINIMAX_MODEL: defaultModel,
  }
}

export function buildVeniceProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.VENICE_API_KEY)
  if (!key) {
    return null
  }

  const defaultBaseUrl = getRouteDefaultBaseUrl('venice')
  const defaultModel = getRouteDefaultModel('venice')
  if (!defaultBaseUrl || !defaultModel) {
    throw new Error('Venice route defaults are missing from integration metadata.')
  }
  const secretSource: SecretValueSource = {
    OPENAI_API_KEY: key,
    VENICE_API_KEY: key,
  }

  return {
    OPENAI_BASE_URL:
      sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
      sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL, secretSource) ||
      defaultBaseUrl,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL, secretSource),
      ) ||
      defaultModel,
    OPENAI_API_KEY: key,
    VENICE_API_KEY: key,
  }
}

export function buildXiaomiMimoProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.MIMO_API_KEY)
  if (!key) {
    return null
  }

  const defaultBaseUrl = getRouteDefaultBaseUrl('xiaomi-mimo')
  const defaultModel = getRouteDefaultModel('xiaomi-mimo')
  if (!defaultBaseUrl || !defaultModel) {
    throw new Error('Xiaomi MiMo route defaults are missing from integration metadata.')
  }
  const secretSource: SecretValueSource = {
    OPENAI_API_KEY: key,
    MIMO_API_KEY: key,
  }

  return {
    OPENAI_BASE_URL:
      normalizeXiaomiMimoBaseUrl(
        sanitizeProviderConfigValue(options.baseUrl, secretSource),
      ) ||
      normalizeXiaomiMimoBaseUrl(
        sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL, secretSource),
      ) ||
      defaultBaseUrl,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL, secretSource),
      ) ||
      defaultModel,
    OPENAI_API_KEY: key,
    MIMO_API_KEY: key,
  }
}

export function buildGeminiProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  authMode?: 'api-key' | 'access-token' | 'adc'
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const authMode = options.authMode ?? 'api-key'
  const key = sanitizeApiKey(
    options.apiKey ??
      processEnv.GEMINI_API_KEY ??
      processEnv.GOOGLE_API_KEY,
  )
  if (authMode === 'api-key' && !key) {
    return null
  }

  const secretSource: SecretValueSource = key ? { GEMINI_API_KEY: key } : {}

  const env: ProfileEnv = {
    GEMINI_AUTH_MODE: authMode,
    GEMINI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.GEMINI_MODEL, secretSource),
      ) ||
      DEFAULT_GEMINI_MODEL,
  }

  if (authMode === 'api-key' && key) {
    env.GEMINI_API_KEY = key
  }

  const baseUrl =
    sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
    sanitizeProviderConfigValue(processEnv.GEMINI_BASE_URL, secretSource)
  if (baseUrl) {
    env.GEMINI_BASE_URL = baseUrl
  }

  return env
}

export function buildOpenAIProfileEnv(options: {
  goal: RecommendationGoal
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  apiFormat?: 'chat_completions' | 'responses' | null
  authHeader?: string | null
  authScheme?: 'bearer' | 'raw' | null
  authHeaderValue?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.OPENAI_API_KEY)
  const authHeaderValue = sanitizeApiKey(
    options.authHeaderValue ?? processEnv.OPENAI_AUTH_HEADER_VALUE,
  )
  if (!key && !authHeaderValue) {
    return null
  }

  const defaultModel = getGoalDefaultOpenAIModel(options.goal)
  const secretSource: SecretValueSource = {
    OPENAI_API_KEY: key,
    OPENAI_AUTH_HEADER_VALUE: authHeaderValue,
  }
  const shellOpenAIModel = normalizeProfileModel(
    sanitizeProviderConfigValue(
      processEnv.OPENAI_MODEL,
      secretSource,
    ),
  )
  const shellOpenAIBaseUrl = sanitizeProviderConfigValue(
    processEnv.OPENAI_BASE_URL,
    secretSource,
  )
  const shellOpenAIRequest = resolveProviderRequest({
    model: shellOpenAIModel,
    baseUrl: shellOpenAIBaseUrl,
    fallbackModel: defaultModel,
    apiFormat: processEnv.OPENAI_API_FORMAT,
  })
  const useShellOpenAIConfig = shellOpenAIRequest.transport !== 'codex_responses'

  return {
    OPENAI_BASE_URL:
      sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
      (useShellOpenAIConfig ? shellOpenAIBaseUrl : undefined) ||
      DEFAULT_OPENAI_BASE_URL,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      (useShellOpenAIConfig ? shellOpenAIModel : undefined) ||
      defaultModel,
    ...(options.apiFormat ? { OPENAI_API_FORMAT: options.apiFormat } : {}),
    ...(options.authHeader ? { OPENAI_AUTH_HEADER: options.authHeader } : {}),
    ...(options.authScheme ? { OPENAI_AUTH_SCHEME: options.authScheme } : {}),
    ...(authHeaderValue ? { OPENAI_AUTH_HEADER_VALUE: authHeaderValue } : {}),
    ...(key ? { OPENAI_API_KEY: key } : {}),
  }
}

export function buildCodexProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  credentialSource?: 'oauth' | 'existing'
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.CODEX_API_KEY)
  const credentialEnv = key
    ? ({ ...processEnv, CODEX_API_KEY: key } as NodeJS.ProcessEnv)
    : processEnv
  const credentials = resolveCodexApiCredentials(credentialEnv)
  if (!credentials.apiKey || !credentials.accountId) {
    return null
  }
  const credentialSource =
    options.credentialSource ??
    (credentials.source === 'secure-storage' ? 'oauth' : 'existing')

  const env: ProfileEnv = {
    OPENAI_BASE_URL: options.baseUrl || DEFAULT_CODEX_BASE_URL,
    OPENAI_MODEL: options.model || 'codexplan',
    CODEX_CREDENTIAL_SOURCE: credentialSource,
  }

  if (key) {
    env.CODEX_API_KEY = key
  }

  env.CHATGPT_ACCOUNT_ID = credentials.accountId

  return env
}

export function buildMistralProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.MISTRAL_API_KEY)
  if (!key) {
    return null
  }

  const env: ProfileEnv = {
    MISTRAL_API_KEY: key,
    MISTRAL_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, { MISTRAL_API_KEY: key }),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(
          processEnv.MISTRAL_MODEL,
          { MISTRAL_API_KEY: key },
        ),
      ) ||
      DEFAULT_MISTRAL_MODEL,
  }

  const baseUrl =
    sanitizeProviderConfigValue(options.baseUrl, { MISTRAL_API_KEY: key }) ||
    sanitizeProviderConfigValue(
      processEnv.MISTRAL_BASE_URL,
      { MISTRAL_API_KEY: key },
    )
  if (baseUrl) {
    env.MISTRAL_BASE_URL = baseUrl
  }

  return env
}

export function buildBankrProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv | null {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.BNKR_API_KEY)
  if (!key) {
    return null
  }

  const env: ProfileEnv = {
    BNKR_API_KEY: key,
    BANKR_MODEL:
      sanitizeProviderConfigValue(options.model, { BNKR_API_KEY: key }) ||
      sanitizeProviderConfigValue(
        processEnv.BANKR_MODEL,
        { BNKR_API_KEY: key },
      ) ||
      'claude-opus-4.6',
  }

  const baseUrl =
    sanitizeProviderConfigValue(options.baseUrl, { BNKR_API_KEY: key }) ||
    sanitizeProviderConfigValue(
      processEnv.BANKR_BASE_URL,
      { BNKR_API_KEY: key },
    )
  if (baseUrl) {
    env.BANKR_BASE_URL = baseUrl
  }

  return env
}

function buildXaiProfileEnv(options: {
  model?: string | null
  baseUrl?: string | null
  apiKey?: string | null
  processEnv?: NodeJS.ProcessEnv
}): ProfileEnv {
  const processEnv = options.processEnv ?? process.env
  const key = sanitizeApiKey(options.apiKey ?? processEnv.XAI_API_KEY)
  const secretSource: SecretValueSource = {
    OPENAI_API_KEY: key,
    XAI_API_KEY: key,
  }
  const defaultBaseUrl = getRouteDefaultBaseUrl('xai') ?? 'https://api.x.ai/v1'
  const defaultModel = getRouteDefaultModel('xai') ?? 'grok-4.3'
  const env: ProfileEnv = {
    OPENAI_BASE_URL:
      sanitizeProviderConfigValue(options.baseUrl, secretSource) ||
      sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL, secretSource) ||
      defaultBaseUrl,
    OPENAI_MODEL:
      normalizeProfileModel(
        sanitizeProviderConfigValue(options.model, secretSource),
      ) ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL, secretSource),
      ) ||
      defaultModel,
  }

  if (key) {
    env.OPENAI_API_KEY = key
    env.XAI_API_KEY = key
  }

  return env
}

function getCompatibilityProfileFlag(
  compatibilityMode: CompatibilityProfileMode,
):
  | 'CLAUDE_CODE_USE_OPENAI'
  | 'CLAUDE_CODE_USE_GITHUB'
  | 'CLAUDE_CODE_USE_GEMINI'
  | 'CLAUDE_CODE_USE_MISTRAL'
  | 'CLAUDE_CODE_USE_BEDROCK'
  | 'CLAUDE_CODE_USE_VERTEX'
  | undefined {
  switch (compatibilityMode) {
    case 'openai':
      return 'CLAUDE_CODE_USE_OPENAI'
    case 'github':
      return 'CLAUDE_CODE_USE_GITHUB'
    case 'gemini':
      return 'CLAUDE_CODE_USE_GEMINI'
    case 'mistral':
      return 'CLAUDE_CODE_USE_MISTRAL'
    case 'bedrock':
      return 'CLAUDE_CODE_USE_BEDROCK'
    case 'vertex':
      return 'CLAUDE_CODE_USE_VERTEX'
    default:
      return undefined
  }
}

export function clearManagedProfileEnv(
  targetEnv: NodeJS.ProcessEnv,
): void {
  for (const key of PROFILE_ENV_KEYS) {
    delete targetEnv[key]
  }
}

export function buildCompatibilityProcessEnv(options: {
  compatibilityMode: CompatibilityProfileMode
  profileEnv: ProfileEnv
  processEnv?: NodeJS.ProcessEnv
}): NodeJS.ProcessEnv {
  const env = { ...(options.processEnv ?? process.env) }
  const nextEnv: NodeJS.ProcessEnv = { ...options.profileEnv }
  const flag = getCompatibilityProfileFlag(options.compatibilityMode)

  if (flag) {
    nextEnv[flag] = '1'
  }

  applyProfileEnvToProcessEnv(env, nextEnv)
  return env
}

export function buildCodexOAuthProfileEnv(
  tokens: {
    accessToken: string
    idToken?: string
    accountId?: string
  },
): ProfileEnv | null {
  const accountId =
    tokens.accountId ??
    parseChatgptAccountId(tokens.idToken) ??
    parseChatgptAccountId(tokens.accessToken)

  if (!accountId) {
    return null
  }

  return {
    OPENAI_BASE_URL: DEFAULT_CODEX_BASE_URL,
    OPENAI_MODEL: 'codexplan',
    CHATGPT_ACCOUNT_ID: accountId,
    CODEX_CREDENTIAL_SOURCE: 'oauth',
  }
}

export function createProfileFile(
  profile: ProviderProfile,
  env: ProfileEnv,
): ProfileFile {
  return {
    profile,
    env,
    createdAt: new Date().toISOString(),
  }
}

export function isPersistedCodexOAuthProfile(
  persisted: ProfileFile | null,
): boolean {
  return (
    persisted?.profile === 'codex' &&
    persisted.env.CODEX_CREDENTIAL_SOURCE === 'oauth'
  )
}

export function clearPersistedCodexOAuthProfile(
  options?: ProfileFileLocation,
): string | null {
  let removedPath: string | null = null

  for (const filePath of resolveProfileFileCleanupPaths(options)) {
    const persisted = readProfileFile(filePath)
    if (isPersistedCodexOAuthProfile(persisted)) {
      rmSync(filePath, { force: true })
      removedPath ??= filePath
    }
  }

  return removedPath
}

export function loadProfileFile(options?: ProfileFileLocation): ProfileFile | null {
  for (const filePath of resolveProfileFileReadPaths(options)) {
    const profile = readProfileFile(filePath)
    if (profile) {
      return profile
    }
  }

  return null
}

export function saveProfileFile(
  profileFile: ProfileFile,
  options?: ProfileFileLocation,
): string {
  const filePath = resolveProfileFilePath(options)
  ensureProfileDirectory(filePath)
  writeFileSync(filePath, JSON.stringify(profileFile, null, 2), {
    encoding: 'utf8',
    mode: 0o600,
  })
  return filePath
}

export function deleteProfileFile(options?: ProfileFileLocation): string {
  const filePath = resolveProfileFilePath(options)
  const cleanupPaths = new Set(resolveProfileFileCleanupPaths(options))

  for (const cleanupPath of cleanupPaths) {
    rmSync(cleanupPath, { force: true })
  }

  return filePath
}

export function hasExplicitProviderSelection(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  // If env was already applied from a provider profile, preserve it.
  if (processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1') {
    return true
  }

  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)
  )
}

function hasConcreteProviderSelection(
  processEnv: NodeJS.ProcessEnv = process.env,
): boolean {
  if (processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1') {
    return true
  }

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_OPENAI)) {
    return (
      sanitizeProviderConfigValue(processEnv.OPENAI_BASE_URL) !== undefined ||
      sanitizeProviderConfigValue(processEnv.OPENAI_API_BASE) !== undefined ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL),
      ) !== undefined
    )
  }

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_GEMINI)) {
    return (
      sanitizeProviderConfigValue(processEnv.GEMINI_BASE_URL) !== undefined ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.GEMINI_MODEL),
      ) !== undefined ||
      sanitizeApiKey(processEnv.GEMINI_API_KEY) !== undefined ||
      sanitizeApiKey(processEnv.GOOGLE_API_KEY) !== undefined
    )
  }

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_MISTRAL)) {
    return (
      sanitizeProviderConfigValue(processEnv.MISTRAL_BASE_URL) !== undefined ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.MISTRAL_MODEL),
      ) !== undefined ||
      sanitizeApiKey(processEnv.MISTRAL_API_KEY) !== undefined
    )
  }

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_GITHUB)) {
    return (
      sanitizeApiKey(processEnv.GITHUB_TOKEN) !== undefined ||
      sanitizeApiKey(processEnv.GH_TOKEN) !== undefined ||
      normalizeProfileModel(
        sanitizeProviderConfigValue(processEnv.OPENAI_MODEL),
      ) !== undefined
    )
  }

  return (
    isEnvTruthy(processEnv.CLAUDE_CODE_USE_BEDROCK) ||
    isEnvTruthy(processEnv.CLAUDE_CODE_USE_VERTEX) ||
    isEnvTruthy(processEnv.CLAUDE_CODE_USE_FOUNDRY)
  )
}

export function selectAutoProfile(
  recommendedOllamaModel: string | null,
): ProviderProfile {
  return recommendedOllamaModel ? 'ollama' : 'openai'
}

export async function buildLaunchEnv(options: {
  profile: ProviderProfile
  persisted: ProfileFile | null
  goal: RecommendationGoal
  processEnv?: NodeJS.ProcessEnv
  getOllamaChatBaseUrl?: (baseUrl?: string) => string
  resolveOllamaDefaultModel?: (goal: RecommendationGoal) => Promise<string>
  getAtomicChatChatBaseUrl?: (baseUrl?: string) => string
  resolveAtomicChatDefaultModel?: () => Promise<string | null>
  readGeminiAccessToken?: () => string | undefined
}): Promise<NodeJS.ProcessEnv> {
  const processEnv = options.processEnv ?? process.env
  const persistedEnv =
    options.persisted?.profile === options.profile
      ? options.persisted.env ?? {}
      : {}
  const persistedOpenAIModel = normalizeProfileModel(
    sanitizeProviderConfigValue(
      persistedEnv.OPENAI_MODEL,
      persistedEnv,
    ),
  )
  const persistedOpenAIBaseUrl = sanitizeProviderConfigValue(
    persistedEnv.OPENAI_BASE_URL,
    persistedEnv,
  )
  const persistedOpenAIApiFormat = persistedEnv.OPENAI_API_FORMAT
  const persistedOpenAIAuthHeader = persistedEnv.OPENAI_AUTH_HEADER
  const persistedOpenAIAuthScheme = persistedEnv.OPENAI_AUTH_SCHEME
  const persistedOpenAIAuthHeaderValue = sanitizeApiKey(
    persistedEnv.OPENAI_AUTH_HEADER_VALUE,
  )
  const persistedCustomHeaders = persistedEnv.ANTHROPIC_CUSTOM_HEADERS
  const shellCustomHeaders = processEnv.ANTHROPIC_CUSTOM_HEADERS
  const shellOpenAIModel = normalizeProfileModel(
    sanitizeProviderConfigValue(
      processEnv.OPENAI_MODEL,
      processEnv as SecretValueSource,
    ),
  )
  const shellOpenAIBaseUrl = sanitizeProviderConfigValue(
    processEnv.OPENAI_BASE_URL,
    processEnv as SecretValueSource,
  )
  const persistedGeminiModel = normalizeProfileModel(
    sanitizeProviderConfigValue(
      persistedEnv.GEMINI_MODEL,
      persistedEnv,
    ),
  )
  const persistedGeminiBaseUrl = sanitizeProviderConfigValue(
    persistedEnv.GEMINI_BASE_URL,
    persistedEnv,
  )
  const shellGeminiModel = normalizeProfileModel(
    sanitizeProviderConfigValue(
      processEnv.GEMINI_MODEL,
      processEnv as SecretValueSource,
    ),
  )
  const shellGeminiBaseUrl = sanitizeProviderConfigValue(
    processEnv.GEMINI_BASE_URL,
    processEnv as SecretValueSource,
  )
  const shellGeminiAccessToken =
    processEnv.GEMINI_ACCESS_TOKEN?.trim() || undefined
  const storedGeminiAccessToken =
    options.readGeminiAccessToken?.() ?? readGeminiAccessToken()

  const shellGeminiKey = sanitizeApiKey(
    processEnv.GEMINI_API_KEY ?? processEnv.GOOGLE_API_KEY,
  )
  const persistedGeminiKey = sanitizeApiKey(persistedEnv.GEMINI_API_KEY)
  const persistedGeminiAuthMode = persistedEnv.GEMINI_AUTH_MODE

  if (hasExplicitProviderSelection(processEnv)) {
    const explicitProfileOverrides: Array<[string, ProviderProfile]> = [
      ['CLAUDE_CODE_USE_GITHUB', 'github'],
      ['CLAUDE_CODE_USE_BEDROCK', 'bedrock'],
      ['CLAUDE_CODE_USE_VERTEX', 'vertex'],
      ['CLAUDE_CODE_USE_MISTRAL', 'mistral'],
      ['CLAUDE_CODE_USE_GEMINI', 'gemini'],
      ['CLAUDE_CODE_USE_OPENAI', 'openai'],
    ]

    for (const [envKey, provider] of explicitProfileOverrides) {
      if (isEnvTruthy(processEnv[envKey])) {
        const isCodexOAuthProfile =
          options.profile === 'codex' &&
          provider === 'openai' &&
          persistedEnv.CODEX_CREDENTIAL_SOURCE === 'oauth'
        if (!isCodexOAuthProfile) {
          options.profile = provider
        }
        break
      }
    }
  }

  if (options.profile === 'github') {
    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'github',
      profileEnv: buildGithubProfileEnv({
        model: shellOpenAIModel || persistedOpenAIModel || 'github:copilot',
        baseUrl: shellOpenAIBaseUrl || persistedOpenAIBaseUrl,
      }),
    })
  }

  if (options.profile === 'anthropic') {
    const anthropicBaseUrl =
      sanitizeProviderConfigValue(processEnv.ANTHROPIC_BASE_URL) ||
      sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_BASE_URL)
    const anthropicApiKey =
      sanitizeApiKey(processEnv.ANTHROPIC_API_KEY) ||
      sanitizeApiKey(persistedEnv.ANTHROPIC_API_KEY)

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'anthropic',
      profileEnv: {
        ...(anthropicBaseUrl
          ? { ANTHROPIC_BASE_URL: anthropicBaseUrl }
          : {}),
        ANTHROPIC_MODEL:
          normalizeProfileModel(
            sanitizeProviderConfigValue(processEnv.ANTHROPIC_MODEL),
          ) ||
          normalizeProfileModel(
            sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_MODEL),
          ) ||
          'claude-sonnet-4-6',
        ...(anthropicApiKey
          ? { ANTHROPIC_API_KEY: anthropicApiKey }
          : {}),
      },
    })
  }

  if (options.profile === 'bedrock') {
    const bedrockBaseUrl =
      sanitizeProviderConfigValue(processEnv.ANTHROPIC_BEDROCK_BASE_URL) ||
      sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_BEDROCK_BASE_URL)

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'bedrock',
      profileEnv: buildBedrockProfileEnv({
        model:
          normalizeProfileModel(
            sanitizeProviderConfigValue(processEnv.ANTHROPIC_MODEL),
          ) ||
          normalizeProfileModel(
            sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_MODEL),
          ) ||
          'claude-sonnet-4-6',
        baseUrl: bedrockBaseUrl,
      }),
    })
  }

  if (options.profile === 'vertex') {
    const vertexBaseUrl =
      sanitizeProviderConfigValue(processEnv.ANTHROPIC_VERTEX_BASE_URL) ||
      sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_VERTEX_BASE_URL)

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'vertex',
      profileEnv: buildVertexProfileEnv({
        model:
          normalizeProfileModel(
            sanitizeProviderConfigValue(processEnv.ANTHROPIC_MODEL),
          ) ||
          normalizeProfileModel(
            sanitizeProviderConfigValue(persistedEnv.ANTHROPIC_MODEL),
          ) ||
          'claude-sonnet-4-6',
        baseUrl: vertexBaseUrl,
      }),
    })
  }

  if (options.profile === 'gemini') {
    const env: ProfileEnv = {
      GEMINI_MODEL:
        shellGeminiModel ||
        persistedGeminiModel ||
        DEFAULT_GEMINI_MODEL,
      GEMINI_BASE_URL:
        shellGeminiBaseUrl ||
        persistedGeminiBaseUrl ||
        DEFAULT_GEMINI_BASE_URL,
    }

    const geminiAuthMode =
      persistedGeminiAuthMode === 'access-token' ||
      persistedGeminiAuthMode === 'adc'
        ? persistedGeminiAuthMode
        : 'api-key'
    const geminiKey = shellGeminiKey || persistedGeminiKey
    if (geminiAuthMode === 'api-key' && geminiKey) {
      env.GEMINI_API_KEY = geminiKey
    }
    env.GEMINI_AUTH_MODE = geminiAuthMode
    if (geminiAuthMode === 'access-token') {
      const geminiAccessToken =
        shellGeminiAccessToken || storedGeminiAccessToken
      if (geminiAccessToken) {
        env.GEMINI_ACCESS_TOKEN = geminiAccessToken
      }
    }

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'gemini',
      profileEnv: env,
    })
  }

  if (options.profile === 'mistral') {
    const shellMistralModel = normalizeProfileModel(
      sanitizeProviderConfigValue(
        processEnv.MISTRAL_MODEL,
      ),
    )
    const persistedMistralModel = normalizeProfileModel(
      sanitizeProviderConfigValue(
        persistedEnv.MISTRAL_MODEL,
      ),
    )
    const shellMistralBaseUrl = sanitizeProviderConfigValue(
      processEnv.MISTRAL_BASE_URL,
    )
    const persistedMistralBaseUrl = sanitizeProviderConfigValue(
      persistedEnv.MISTRAL_BASE_URL,
    )

    const shellMistralKey = sanitizeApiKey(
      processEnv.MISTRAL_API_KEY,
    )
    const persistedMistralKey = sanitizeApiKey(persistedEnv.MISTRAL_API_KEY)
    const mistralKey = shellMistralKey || persistedMistralKey

    const env: ProfileEnv = {
      MISTRAL_MODEL:
        shellMistralModel || persistedMistralModel || DEFAULT_MISTRAL_MODEL,
    }

    if (mistralKey) {
      env.MISTRAL_API_KEY = mistralKey
    }

    if (shellMistralBaseUrl || persistedMistralBaseUrl) {
      env.MISTRAL_BASE_URL = shellMistralBaseUrl || persistedMistralBaseUrl
    }

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'mistral',
      profileEnv: env,
    })
  }

  if (options.profile === 'xai') {
    const xaiKey =
      sanitizeApiKey(processEnv.XAI_API_KEY) ||
      sanitizeApiKey(persistedEnv.XAI_API_KEY) ||
      sanitizeApiKey(processEnv.OPENAI_API_KEY) ||
      sanitizeApiKey(persistedEnv.OPENAI_API_KEY)

    const env = buildXaiProfileEnv({
      model: shellOpenAIModel || persistedOpenAIModel,
      baseUrl: shellOpenAIBaseUrl || persistedOpenAIBaseUrl,
      apiKey: xaiKey,
      processEnv,
    })
    const customHeaders = shellCustomHeaders || persistedCustomHeaders
    if (customHeaders) {
      env.ANTHROPIC_CUSTOM_HEADERS = customHeaders
    }

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'openai',
      profileEnv: env,
    })
  }

  if (options.profile === 'ollama') {
    const getOllamaBaseUrl =
      options.getOllamaChatBaseUrl ?? (() => 'http://localhost:11434/v1')
    const resolveOllamaModel =
      options.resolveOllamaDefaultModel ?? (async () => 'llama3.1:8b')

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'openai',
      profileEnv: {
        OPENAI_BASE_URL: persistedOpenAIBaseUrl || getOllamaBaseUrl(),
        OPENAI_MODEL:
          persistedOpenAIModel ||
          (await resolveOllamaModel(options.goal)),
      },
    })
  }

  if (options.profile === 'atomic-chat') {
    const getAtomicChatBaseUrl =
      options.getAtomicChatChatBaseUrl ?? (() => 'http://127.0.0.1:1337/v1')
    const resolveModel =
      options.resolveAtomicChatDefaultModel ?? (async () => null as string | null)

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'openai',
      profileEnv: {
        OPENAI_BASE_URL: persistedEnv.OPENAI_BASE_URL || getAtomicChatBaseUrl(),
        OPENAI_MODEL:
          persistedEnv.OPENAI_MODEL ||
          (await resolveModel()) ||
          '',
      },
    })
  }

  if (options.profile === 'codex') {
    const isCodexOAuthProfile = persistedEnv.CODEX_CREDENTIAL_SOURCE === 'oauth'
    const codexKey = isCodexOAuthProfile
      ? undefined
      : sanitizeApiKey(processEnv.CODEX_API_KEY) ||
        sanitizeApiKey(persistedEnv.CODEX_API_KEY)
    const liveCodexCredentials = isCodexOAuthProfile
      ? undefined
      : resolveCodexApiCredentials(processEnv)
    const codexAccountId = isCodexOAuthProfile
      ? persistedEnv.CHATGPT_ACCOUNT_ID || persistedEnv.CODEX_ACCOUNT_ID
      : processEnv.CHATGPT_ACCOUNT_ID ||
        processEnv.CODEX_ACCOUNT_ID ||
        liveCodexCredentials?.accountId ||
        persistedEnv.CHATGPT_ACCOUNT_ID ||
        persistedEnv.CODEX_ACCOUNT_ID

    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'openai',
      profileEnv: {
        OPENAI_BASE_URL:
          persistedOpenAIBaseUrl && isCodexBaseUrl(persistedOpenAIBaseUrl)
            ? persistedOpenAIBaseUrl
            : DEFAULT_CODEX_BASE_URL,
        OPENAI_MODEL: persistedOpenAIModel || 'codexplan',
        ...(codexKey ? { CODEX_API_KEY: codexKey } : {}),
        ...(codexAccountId ? { CHATGPT_ACCOUNT_ID: codexAccountId } : {}),
      },
    })
  }

  const defaultOpenAIModel = getGoalDefaultOpenAIModel(options.goal)
  const shellOpenAIRequest = resolveProviderRequest({
    model: shellOpenAIModel,
    baseUrl: shellOpenAIBaseUrl,
    fallbackModel: defaultOpenAIModel,
    apiFormat: processEnv.OPENAI_API_FORMAT,
  })
  const persistedOpenAIRequest = resolveProviderRequest({
    model: persistedOpenAIModel,
    baseUrl: persistedOpenAIBaseUrl,
    fallbackModel: defaultOpenAIModel,
    apiFormat: persistedOpenAIApiFormat,
  })
  const useShellOpenAIConfig = shellOpenAIRequest.transport !== 'codex_responses'
  const usePersistedOpenAIConfig =
    (!persistedOpenAIModel && !persistedOpenAIBaseUrl) ||
    persistedOpenAIRequest.transport !== 'codex_responses'

  const env: ProfileEnv = {
    OPENAI_BASE_URL:
      (useShellOpenAIConfig ? shellOpenAIBaseUrl : undefined) ||
      (usePersistedOpenAIConfig ? persistedOpenAIBaseUrl : undefined) ||
      DEFAULT_OPENAI_BASE_URL,
    OPENAI_MODEL:
      (useShellOpenAIConfig ? shellOpenAIModel : undefined) ||
      (usePersistedOpenAIConfig ? persistedOpenAIModel : undefined) ||
      defaultOpenAIModel,
  }
  const openAIApiFormat =
    parseOpenAICompatibleApiFormat(processEnv.OPENAI_API_FORMAT) ||
    (usePersistedOpenAIConfig ? persistedOpenAIApiFormat : undefined)
  if (openAIApiFormat) {
    env.OPENAI_API_FORMAT = openAIApiFormat
  } else {
    delete env.OPENAI_API_FORMAT
  }
  const openAIAuthHeader =
    processEnv.OPENAI_AUTH_HEADER ||
    (usePersistedOpenAIConfig ? persistedOpenAIAuthHeader : undefined)
  if (openAIAuthHeader) {
    env.OPENAI_AUTH_HEADER = openAIAuthHeader
  } else {
    delete env.OPENAI_AUTH_HEADER
  }
  const openAIAuthScheme =
    (processEnv.OPENAI_AUTH_SCHEME === 'bearer' ||
    processEnv.OPENAI_AUTH_SCHEME === 'raw'
      ? processEnv.OPENAI_AUTH_SCHEME
      : undefined) ||
    (usePersistedOpenAIConfig ? persistedOpenAIAuthScheme : undefined)
  if (openAIAuthScheme) {
    env.OPENAI_AUTH_SCHEME = openAIAuthScheme
  } else {
    delete env.OPENAI_AUTH_SCHEME
  }
  const openAIAuthHeaderValue =
    sanitizeApiKey(processEnv.OPENAI_AUTH_HEADER_VALUE) ||
    (usePersistedOpenAIConfig ? persistedOpenAIAuthHeaderValue : undefined)
  if (openAIAuthHeaderValue) {
    env.OPENAI_AUTH_HEADER_VALUE = openAIAuthHeaderValue
  } else {
    delete env.OPENAI_AUTH_HEADER_VALUE
  }
  const openAIKey = processEnv.OPENAI_API_KEY || persistedEnv.OPENAI_API_KEY
  if (openAIKey) {
    env.OPENAI_API_KEY = openAIKey
  }
  const customHeaders = shellCustomHeaders || persistedCustomHeaders
  if (customHeaders) {
    env.ANTHROPIC_CUSTOM_HEADERS = customHeaders
  }

  return buildCompatibilityProcessEnv({
    processEnv,
    compatibilityMode: 'openai',
    profileEnv: env,
  })
}

export async function buildStartupEnvFromProfile(options?: {
  persisted?: ProfileFile | null
  goal?: RecommendationGoal
  processEnv?: NodeJS.ProcessEnv
  hasConfiguredProviderProfile?: boolean
  getOllamaChatBaseUrl?: (baseUrl?: string) => string
  resolveOllamaDefaultModel?: (goal: RecommendationGoal) => Promise<string>
  readGeminiAccessToken?: () => string | undefined
}): Promise<NodeJS.ProcessEnv> {
  const processEnv = options?.processEnv ?? process.env
  const persisted = options?.persisted ?? loadProfileFile()

  const profileManagedEnv = processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1'
  const hasConfiguredProviderProfile =
    options?.hasConfiguredProviderProfile ?? false

  // The single-profile file in the user config directory is a
  // first-run / fallback mechanism. The newer plural provider-profile
  // system (`/provider` presets + activeProviderProfileId in config) is
  // applied earlier in the bootstrap via applyActiveProviderProfileFromConfig
  // and signals completion with CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED=1.
  //
  // If the plural system has already set env, trust it — do NOT overlay the
  // legacy file. addProviderProfile() does not sync the legacy file, so a
  // stale legacy file (e.g. OpenAI defaults from an earlier manual setup)
  // would otherwise overwrite the correct plural env and surface as the
  // "banner shows gpt-4o / api.openai.com even though my saved profile is
  // Moonshot" bug.
  if (profileManagedEnv) {
    return processEnv
  }

  // If startup already has a concrete provider selection and the modern
  // plural-profile system is configured, keep trusting that selection.
  // This prevents the legacy single-profile file from becoming a silent
  // third precedence layer when `/provider` profiles or explicit env/flags
  // already chose a provider before startup fallback runs.
  if (
    hasConfiguredProviderProfile &&
    hasConcreteProviderSelection(processEnv)
  ) {
    return processEnv
  }

  if (isEnvTruthy(processEnv.CLAUDE_CODE_USE_GITHUB)) {
    return processEnv
  }

  if (!persisted) {
    // No saved profile — default to Codex OAuth / GPT 5.5.
    // If Codex credentials are available (OAuth or existing), use Codex.
    // Otherwise inject the Codex env defaults so the provider picker
    // shows GPT 5.5 as the default model when the user lands on it.
    const codexEnv = buildCodexProfileEnv({})
    if (codexEnv) {
      return buildCompatibilityProcessEnv({
        processEnv,
        compatibilityMode: 'openai',
        profileEnv: codexEnv,
      })
    }
    return buildCompatibilityProcessEnv({
      processEnv,
      compatibilityMode: 'openai',
      profileEnv: {
        OPENAI_BASE_URL: DEFAULT_CODEX_BASE_URL,
        OPENAI_MODEL: 'codexplan',
      },
    })
  }

  return buildLaunchEnv({
    profile: persisted.profile,
    persisted,
    goal:
      options?.goal ??
      normalizeRecommendationGoal(processEnv.OPENCLAUDE_PROFILE_GOAL),
    processEnv,
    getOllamaChatBaseUrl:
      options?.getOllamaChatBaseUrl ?? getOllamaChatBaseUrl,
    resolveOllamaDefaultModel: options?.resolveOllamaDefaultModel,
    readGeminiAccessToken: options?.readGeminiAccessToken,
  })
}

export function applyProfileEnvToProcessEnv(
  targetEnv: NodeJS.ProcessEnv,
  nextEnv: NodeJS.ProcessEnv,
): void {
  clearManagedProfileEnv(targetEnv)
  Object.assign(targetEnv, nextEnv)
}

export async function applySavedProfileToCurrentSession(options: {
  profileFile: ProfileFile
  processEnv?: NodeJS.ProcessEnv
}): Promise<string | null> {
  const processEnv = options.processEnv ?? process.env
  const hasExplicitSelection = hasExplicitProviderSelection(processEnv)
  const profileManagedEnv =
    processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED === '1'

  if (options.profileFile.profile === 'codex' && hasExplicitSelection) {
    const isCodexOAuthProfile =
      options.profileFile.env.CODEX_CREDENTIAL_SOURCE === 'oauth'
    const buildEnvSource = isCodexOAuthProfile
      ? { ...processEnv }
      : processEnv
    if (isCodexOAuthProfile) {
      delete buildEnvSource.CODEX_API_KEY
      delete buildEnvSource.CODEX_ACCOUNT_ID
      delete buildEnvSource.CHATGPT_ACCOUNT_ID
    }
    const explicitEnv = await buildLaunchEnv({
      profile: options.profileFile.profile,
      persisted: options.profileFile,
      goal: normalizeRecommendationGoal(processEnv.OPENCLAUDE_PROFILE_GOAL),
      processEnv: buildEnvSource,
      getOllamaChatBaseUrl,
      readGeminiAccessToken,
    })
    delete explicitEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED
    delete explicitEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID
    const validationEnv = isCodexOAuthProfile
      ? { ...explicitEnv, CODEX_API_KEY: 'codex-oauth-token-for-validation' }
      : explicitEnv
    const validationError = await getProviderValidationError(validationEnv)

    if (profileManagedEnv) {
      delete processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED
      delete processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID
      applyProfileEnvToProcessEnv(processEnv, explicitEnv)
      return validationError
    }

    return (
      validationError ??
      'current session already has an explicit provider selection'
    )
  }

  const baseEnv = { ...processEnv }
  const isCodexOAuthProfile =
    options.profileFile.profile === 'codex' &&
    options.profileFile.env.CODEX_CREDENTIAL_SOURCE === 'oauth'

  delete baseEnv.CLAUDE_CODE_USE_OPENAI
  delete baseEnv.CLAUDE_CODE_USE_GITHUB
  delete baseEnv.CLAUDE_CODE_USE_GEMINI
  delete baseEnv.CLAUDE_CODE_USE_MISTRAL
  delete baseEnv.CLAUDE_CODE_USE_BEDROCK
  delete baseEnv.CLAUDE_CODE_USE_VERTEX
  delete baseEnv.CLAUDE_CODE_USE_FOUNDRY
  delete baseEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED
  delete baseEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID

  if (isCodexOAuthProfile) {
    delete baseEnv.CODEX_API_KEY
    delete baseEnv.CODEX_ACCOUNT_ID
    delete baseEnv.CHATGPT_ACCOUNT_ID
  }

  const nextEnv = await buildLaunchEnv({
    profile: options.profileFile.profile,
    persisted: options.profileFile,
    goal: normalizeRecommendationGoal(processEnv.OPENCLAUDE_PROFILE_GOAL),
    processEnv: baseEnv,
    getOllamaChatBaseUrl,
    readGeminiAccessToken,
  })
  const validationEnv = isCodexOAuthProfile
    ? { ...nextEnv, CODEX_API_KEY: 'codex-oauth-token-for-validation' }
    : nextEnv
  const validationError = await getProviderValidationError(validationEnv)
  if (validationError) {
    return validationError
  }

  delete processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED
  delete processEnv.CLAUDE_CODE_PROVIDER_PROFILE_ENV_APPLIED_ID
  applyProfileEnvToProcessEnv(processEnv, nextEnv)
  return null
}
