import assert from 'node:assert/strict'
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import test from 'node:test'
import {
  MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
  resolveMovScriptWorkspacePaths,
  writeMovScriptWorkspaceConfig,
} from '@movscript/core/workspace/node'
import { writeMovScriptBackendAuth, writeMovScriptBackendConfig } from '@movscript/core/backend/node'
import {
  appServerSpawnEnvironmentFromDistribution,
  distributeAppServerConfigFromMovScriptWorkspace,
} from './appServerConfigDistribution'

test('distributes provider account config into app-server config files', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1/',
    },
    providers: {
      codex: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-test-key',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.apiKeyConfigured, true)
  assert.equal(distribution.accountConfigured, true)
  assert.equal(distribution.accountSource, 'movscript-account')
  assert.equal(distribution.baseURL, 'https://gateway.example/v1')
  assert.equal(distribution.sourceConfigPath, paths.configPath)
  assert.equal(distribution.configTomlPath, join(codexHome, 'config.toml'))
  assert.equal(distribution.authJsonPath, join(codexHome, 'auth.json'))

  const configToml = readFileSync(distribution.configTomlPath, 'utf8')
  assert.match(configToml, /Generated by MovScript/)
  assert.doesNotMatch(configToml, /^model = /m)
  assert.match(configToml, /model_provider = "movscript"/)
  assert.match(configToml, /base_url = "https:\/\/gateway\.example\/v1"/)
  assert.match(configToml, /env_key = "OPENAI_API_KEY"/)
  assert.match(configToml, /wire_api = "responses"/)
  assert.match(configToml, /requires_openai_auth = false/)
  assert.match(configToml, /supports_websockets = true/)

  const authJson = JSON.parse(readFileSync(distribution.authJsonPath, 'utf8'))
  assert.equal(authJson.auth_mode, 'apikey')
  assert.equal(authJson.OPENAI_API_KEY, 'sk-test-key')

  const env = appServerSpawnEnvironmentFromDistribution(distribution, {})
  assert.equal(env.MOVSCRIPT_APP_SERVER_HOME, codexHome)
  assert.equal(env.CODEX_HOME, codexHome)
  assert.equal(env.OPENAI_API_KEY, 'sk-test-key')
  assert.equal(env.MOVSCRIPT_APP_SERVER_CONFIG_SOURCE, paths.configPath)
  assert.equal('MOVSCRIPT_CODEX_CONFIG_SOURCE' in env, false)
})

test('distributes Mova account config from its own provider record into the Mova managed home', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-mova-config-'))
  const movaHome = join(workspaceDir, '.movscript', '.mova')
  const defaultPaths = resolveMovScriptWorkspacePaths(workspaceDir)
  const movaConfigPaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'mova' })
  writeMovScriptWorkspaceConfig(defaultPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-codex-key',
        },
      },
    },
  })
  writeMovScriptWorkspaceConfig(movaConfigPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:01.000Z',
    providers: {
      mova: {
        appServer: {
          compatibilityHomeEnvNames: ['CODEX_HOME'],
        },
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-mova-key',
          baseURL: 'https://mova-gateway.example/v1/',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: movaHome,
    providerKey: 'mova',
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountSource, 'movscript-account')
  assert.equal(distribution.baseURL, 'https://mova-gateway.example/v1')
  assert.equal(distribution.sourceConfigPath, movaConfigPaths.configPath)
  assert.equal(distribution.configTomlPath, join(movaHome, 'config.toml'))
  assert.equal(distribution.authJsonPath, join(movaHome, 'auth.json'))
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).OPENAI_API_KEY, 'sk-mova-key')
  const env = appServerSpawnEnvironmentFromDistribution(distribution, {})
  assert.equal(env.MOVSCRIPT_APP_SERVER_PROVIDER, 'mova')
  assert.equal(env.MOVSCRIPT_APP_SERVER_HOME, movaHome)
  assert.equal(env.MOVA_HOME, movaHome)
  assert.equal(env.CODEX_HOME, movaHome)
  assert.equal(env.OPENAI_API_KEY, 'sk-mova-key')
})

test('uses backend provider base URL for backendKey app-server config', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-backend-provider-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    environment: {
      MOVSCRIPT_APP_SERVER_API_KEY: 'mgw_backend_managed_key',
    },
    providers: {
      codex: {
        providerRef: 'backend:501',
        authSource: 'model-provider',
        baseURL: 'http://localhost:8766/api/v1',
        config: { mode: 'backendKey', modelProviderRef: 'backend:501' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:501' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountSource, 'movscript-environment')
  assert.equal(distribution.baseURL, 'http://127.0.0.1:8766/v1')
  const configToml = readFileSync(distribution.configTomlPath, 'utf8')
  assert.match(configToml, /base_url = "http:\/\/127\.0\.0\.1:8766\/v1"/)
  assert.match(configToml, /supports_websockets = false/)
})

test('falls back to workspace backend base URL for existing backendKey app-server config', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-backend-provider-existing-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptBackendConfig(workspaceDir, { baseURL: 'https://backend.example/api/v1' })
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    environment: {
      MOVSCRIPT_APP_SERVER_API_KEY: 'mgw_backend_managed_key',
    },
    providers: {
      codex: {
        providerRef: 'backend:501',
        authSource: 'model-provider',
        config: { mode: 'backendKey', modelProviderRef: 'backend:501' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:501' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.baseURL, 'https://backend.example/v1')
  const configToml = readFileSync(distribution.configTomlPath, 'utf8')
  assert.match(configToml, /base_url = "https:\/\/backend\.example\/v1"/)
  assert.match(configToml, /supports_websockets = false/)
})

test('uses managed home provider when caller passes default provider key', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-default-key-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const defaultPaths = resolveMovScriptWorkspacePaths(workspaceDir)
  const codexPaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'codex' })
  writeMovScriptWorkspaceConfig(defaultPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
  })
  writeMovScriptWorkspaceConfig(codexPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:01.000Z',
    environment: {
      MOVSCRIPT_APP_SERVER_API_KEY: 'mgw_backend_managed_key',
    },
    providers: {
      codex: {
        providerRef: 'backend:1',
        authSource: 'model-provider',
        baseURL: 'http://localhost:8765/v1',
        config: { mode: 'backendKey', modelProviderRef: 'backend:1' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:1' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    providerKey: 'default',
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.providerKey, 'codex')
  assert.equal(distribution.sourceConfigPath, codexPaths.configPath)
  assert.equal(distribution.baseURL, 'http://127.0.0.1:8765/v1')
  assert.match(readFileSync(distribution.configTomlPath, 'utf8'), /base_url = "http:\/\/127\.0\.0\.1:8765\/v1"/)
})

test('uses backend session token for backend provider app-server auth', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-backend-session-token-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'codex' })
  writeMovScriptBackendAuth(workspaceDir, {
    token: 'mv1.backend-session-token',
    user: { id: 1, username: 'admin' },
  })
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    providers: {
      codex: {
        providerRef: 'backend:1',
        authSource: 'model-provider',
        baseURL: 'http://localhost:8765/v1',
        config: { mode: 'backendKey', modelProviderRef: 'backend:1' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:1' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    providerKey: 'codex',
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountConfigured, true)
  assert.equal(distribution.accountSource, 'movscript-backend-session')
  assert.equal(distribution.baseURL, 'http://127.0.0.1:8765/v1')
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).OPENAI_API_KEY, 'mv1.backend-session-token')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).OPENAI_API_KEY, 'mv1.backend-session-token')
})

test('rejects upstream provider keys for backend app-server gateway auth', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-backend-upstream-key-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'codex' })
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    environment: {
      MOVSCRIPT_APP_SERVER_API_KEY: 'sk-upstream-provider-key',
    },
    providers: {
      codex: {
        providerRef: 'backend:1',
        authSource: 'model-provider',
        baseURL: 'http://localhost:8765/v1',
        config: { mode: 'backendKey', modelProviderRef: 'backend:1' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:1' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    providerKey: 'codex',
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, false)
  assert.equal(distribution.accountConfigured, false)
  assert.equal(distribution.accountSource, 'none')
  assert.match(distribution.warning ?? '', /model gateway API key/)
})

test('overwrites backend provider config.toml even when backend account is missing', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-backend-no-account-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'codex' })
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    providers: {
      codex: {
        providerRef: 'backend:1',
        authSource: 'model-provider',
        baseURL: 'http://localhost:8765/v1',
        config: { mode: 'backendKey', modelProviderRef: 'backend:1' },
        auth: { mode: 'backendKey', modelProviderRef: 'backend:1' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    providerKey: 'codex',
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, false)
  assert.equal(distribution.accountSource, 'none')
  assert.match(readFileSync(distribution.configTomlPath, 'utf8'), /model_provider = "movscript"/)
  assert.match(readFileSync(distribution.configTomlPath, 'utf8'), /base_url = "http:\/\/127\.0\.0\.1:8765\/v1"/)
})

test('distributes a custom app-server provider from its own managed provider profile config', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-claude-config-'))
  const claudeHome = join(workspaceDir, '.movscript', '.claude')
  const claudeProfilePaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'claude' })
  writeMovScriptWorkspaceConfig(claudeProfilePaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    modelConfig: {
      model: 'claude-test',
      apiKind: 'anthropic_messages',
      baseURL: 'https://claude-gateway.example/v1/',
    },
    providers: {
      claude: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-claude-key',
          baseURL: 'https://claude-agent.example/v1/',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: claudeHome,
    providerKey: 'claude',
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.providerKey, 'claude')
  assert.equal(distribution.sourceConfigPath, claudeProfilePaths.configPath)
  assert.equal(distribution.home, claudeHome)
  assert.equal(distribution.baseURL, 'https://claude-agent.example/v1')

  const env = appServerSpawnEnvironmentFromDistribution(distribution, {})
  assert.equal(env.MOVSCRIPT_APP_SERVER_PROVIDER, 'claude')
  assert.equal(env.MOVSCRIPT_APP_SERVER_HOME, claudeHome)
  assert.equal(env.CLAUDE_HOME, claudeHome)
  assert.equal('CODEX_HOME' in env, false)
  assert.equal(env.OPENAI_API_KEY, 'sk-claude-key')
})

test('infers Mova distribution from the managed Mova home when provider key is omitted', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-mova-config-inferred-'))
  const movaHome = join(workspaceDir, '.movscript', '.mova')
  const defaultPaths = resolveMovScriptWorkspacePaths(workspaceDir)
  const movaConfigPaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'mova' })
  writeMovScriptWorkspaceConfig(defaultPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-codex-key',
        },
      },
    },
  })
  writeMovScriptWorkspaceConfig(movaConfigPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:01.000Z',
    providers: {
      mova: {
        appServer: {
          compatibilityHomeEnvNames: ['CODEX_HOME'],
        },
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-inferred-mova-key',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: movaHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.sourceConfigPath, movaConfigPaths.configPath)
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).OPENAI_API_KEY, 'sk-inferred-mova-key')
})

test('infers custom app-server provider distribution from its managed provider home', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-studio-config-inferred-'))
  const studioHome = join(workspaceDir, '.movscript', '.studio-agent')
  const studioConfigPaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'studio-agent' })
  writeMovScriptWorkspaceConfig(studioConfigPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-06T00:00:00.000Z',
    providers: {
      'studio-agent': {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-studio-key',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: studioHome,
    now: new Date('2026-06-06T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.providerKey, 'studio-agent')
  assert.equal(distribution.sourceConfigPath, studioConfigPaths.configPath)
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).OPENAI_API_KEY, 'sk-studio-key')
})

test('uses a provider profile config as app-server source while inheriting default runtime fields', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-profile-config-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const defaultPaths = resolveMovScriptWorkspacePaths(workspaceDir)
  const codexConfigPaths = resolveMovScriptWorkspacePaths(workspaceDir, { configDirName: 'codex' })
  writeMovScriptWorkspaceConfig(defaultPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      apiKind: 'openai_responses',
      baseURL: 'https://default-gateway.example/v1/',
    },
  })
  writeMovScriptWorkspaceConfig(codexConfigPaths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:01.000Z',
    providers: {
      codex: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-profile-key',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.sourceConfigPath, codexConfigPaths.configPath)
  assert.equal(distribution.baseURL, 'https://default-gateway.example/v1')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).OPENAI_API_KEY, 'sk-profile-key')
})

test('inherits existing MovScript-managed provider auth when no explicit account is configured', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-no-key-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1',
    },
  })
  mkdirSync(codexHome, { recursive: true })
  writeFileSync(join(codexHome, 'auth.json'), '{"OPENAI_API_KEY":"managed-home-key"}\n')

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.apiKeyConfigured, true)
  assert.equal(distribution.accountConfigured, true)
  assert.equal(distribution.accountSource, 'managed-home')
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).OPENAI_API_KEY, 'managed-home-key')
  const env = appServerSpawnEnvironmentFromDistribution(distribution, { OPENAI_API_KEY: 'external-key' })
  assert.equal(env.OPENAI_API_KEY, 'managed-home-key')
})

test('keeps app-server launch hash stable across distribution timestamps', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-stable-hash-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1',
    },
    providers: {
      codex: {
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-test-key',
        },
      },
    },
  })

  const first = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })
  const second = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:04.000Z'),
  })

  assert.notEqual(first.distributedAt, second.distributedAt)
  assert.equal(first.hash, second.hash)
})

test('clears provider auth only when MovScript explicitly disables the account', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-none-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1',
    },
    providers: {
      codex: {
        auth: { mode: 'none' },
      },
    },
  })
  mkdirSync(codexHome, { recursive: true })
  writeFileSync(join(codexHome, 'auth.json'), '{"OPENAI_API_KEY":"stale"}\n')

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, false)
  assert.equal(distribution.apiKeyConfigured, false)
  assert.equal(distribution.accountConfigured, false)
  assert.equal(distribution.accountSource, 'none')
  assert.throws(() => readFileSync(distribution.authJsonPath, 'utf8'), /ENOENT/)
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, { OPENAI_API_KEY: 'external-key' }).OPENAI_API_KEY, undefined)
})

test('does not create provider home when no provider account can be projected', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-no-home-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        auth: { mode: 'none' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.accountConfigured, false)
  assert.equal(existsSync(codexHome), false)
})

test('inherits managed provider ChatGPT auth without forcing API key env', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-chatgpt-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://api.openai.com/v1',
    },
  })
  mkdirSync(codexHome, { recursive: true })
  writeFileSync(join(codexHome, 'auth.json'), JSON.stringify({
    auth_mode: 'chatgpt',
    tokens: {
      id_token: 'id-token',
      access_token: 'access-token',
      refresh_token: 'refresh-token',
    },
    last_refresh: '2026-06-04T00:00:00.000Z',
  }, null, 2))

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.apiKeyConfigured, false)
  assert.equal(distribution.accountConfigured, true)
  assert.equal(distribution.accountSource, 'managed-home')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, { OPENAI_API_KEY: 'external-key' }).OPENAI_API_KEY, undefined)
  const configToml = readFileSync(distribution.configTomlPath, 'utf8')
  assert.match(configToml, /model_provider = "openai"/)
  assert.doesNotMatch(configToml, /env_key = "OPENAI_API_KEY"/)
})

test('distributes user supplied provider base URL and API key', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-custom-key-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        config: { mode: 'customApiKey' },
        auth: {
          mode: 'apiKey',
          apiKey: 'sk-user-key',
          baseURL: 'https://user-gateway.example/v1/',
        },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountSource, 'movscript-account')
  assert.equal(distribution.baseURL, 'https://user-gateway.example/v1')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).OPENAI_API_KEY, 'sk-user-key')
  assert.match(readFileSync(distribution.configTomlPath, 'utf8'), /base_url = "https:\/\/user-gateway\.example\/v1"/)
})

test('inherits local app-server home provider config and auth without copying a home-level model', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-local-'))
  const localHome = mkdtempSync(join(tmpdir(), 'movscript-local-home-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeFileSync(join(localHome, 'config.toml'), 'model = "local-codex-model"\nmodel_provider = "openai"\n')
  writeFileSync(join(localHome, 'auth.json'), JSON.stringify({
    auth_mode: 'chatgpt',
    tokens: { access_token: 'local-access-token' },
    last_refresh: '2026-06-04T00:00:00.000Z',
  }, null, 2))
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        config: { mode: 'local-home', localHome },
        auth: { mode: 'local-home', localHome },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountSource, 'local-home')
  const configToml = readFileSync(distribution.configTomlPath, 'utf8')
  assert.equal(configToml, 'model_provider = "openai"\n')
  assert.doesNotMatch(configToml, /^model = /m)
  assert.equal(JSON.parse(readFileSync(distribution.authJsonPath, 'utf8')).tokens.access_token, 'local-access-token')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, { OPENAI_API_KEY: 'external-key' }).OPENAI_API_KEY, undefined)
})

test('maps legacy local provider home mode to Mova local-home distribution', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-mova-config-legacy-local-'))
  const localHome = mkdtempSync(join(tmpdir(), 'movscript-legacy-local-home-'))
  const movaHome = join(workspaceDir, '.movscript', '.mova')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  const legacyMode = ['local', 'Codex'].join('')
  writeFileSync(join(localHome, 'auth.json'), JSON.stringify({
    OPENAI_API_KEY: 'sk-legacy-local',
  }, null, 2))
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      mova: {
        config: { mode: legacyMode, localHome },
        auth: { mode: legacyMode, localHome },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    providerKey: 'mova',
    home: movaHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.providerKey, 'mova')
  assert.equal(distribution.accountSource, 'local-home')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).MOVA_HOME, movaHome)
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).OPENAI_API_KEY, 'sk-legacy-local')
})

test('custom provider config mode does not overwrite user edited config files', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-manual-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  mkdirSync(codexHome, { recursive: true })
  writeFileSync(join(codexHome, 'config.toml'), 'model = "manual-model"\n')
  writeFileSync(join(codexHome, 'auth.json'), '{"OPENAI_API_KEY":"manual-key"}\n')
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    providers: {
      codex: {
        config: { mode: 'customConfig' },
        auth: { mode: 'customConfig' },
      },
    },
  })

  const distribution = distributeAppServerConfigFromMovScriptWorkspace({
    workspaceDir,
    home: codexHome,
    now: new Date('2026-06-04T01:02:03.000Z'),
  })

  assert.equal(distribution.ok, true)
  assert.equal(distribution.accountSource, 'custom-config')
  assert.equal(readFileSync(distribution.configTomlPath, 'utf8'), 'model = "manual-model"\n')
  assert.equal(appServerSpawnEnvironmentFromDistribution(distribution, {}).OPENAI_API_KEY, 'manual-key')
})

test('changes distribution hash when only API key changes', () => {
  const workspaceDir = mkdtempSync(join(tmpdir(), 'movscript-codex-config-key-change-'))
  const codexHome = join(workspaceDir, '.movscript', '.codex')
  const paths = resolveMovScriptWorkspacePaths(workspaceDir)
  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:00.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1',
    },
    providers: { codex: { auth: { mode: 'apiKey', apiKey: 'sk-first' } } },
  })
  const first = distributeAppServerConfigFromMovScriptWorkspace({ workspaceDir, home: codexHome, now: new Date('2026-06-04T01:02:03.000Z') })

  writeMovScriptWorkspaceConfig(paths.configPath, {
    schema: MOVSCRIPT_WORKSPACE_CONFIG_SCHEMA,
    updatedAt: '2026-06-04T00:00:01.000Z',
    modelConfig: {
      model: 'gpt-test-codex',
      apiKind: 'openai_responses',
      baseURL: 'https://gateway.example/v1',
    },
    providers: { codex: { auth: { mode: 'apiKey', apiKey: 'sk-second' } } },
  })
  const second = distributeAppServerConfigFromMovScriptWorkspace({ workspaceDir, home: codexHome, now: new Date('2026-06-04T01:02:03.000Z') })

  assert.notEqual(first.hash, second.hash)
  assert.equal(appServerSpawnEnvironmentFromDistribution(second, {}).OPENAI_API_KEY, 'sk-second')
})
