import test from 'node:test'
import assert from 'node:assert/strict'
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs'
import { join } from 'path'
import { SMALL_MODEL_USE_MAIN } from '../packages/shared/src/app-config.ts'
import { clearConfigCaches } from '../apps/desktop/src/main/config-loader.ts'

function testTempDir(prefix: string) {
  const parent = join(process.cwd(), '.open-cowork-test')
  mkdirSync(parent, { recursive: true })
  return mkdtempSync(join(parent, prefix))
}

function writeAskPermissionConfig(configDir: string) {
  mkdirSync(configDir, { recursive: true })
  writeFileSync(join(configDir, 'config.jsonc'), `{
  "permissions": {
    "bash": "ask",
    "fileWrite": "ask",
    "task": "allow",
    "web": "allow",
    "webSearch": true
  }
}
`)
}

function writeEmptyConfig(configDir: string) {
  mkdirSync(configDir, { recursive: true })
  writeFileSync(join(configDir, 'config.jsonc'), '{}\n')
}

function writeProviderDefaultConfig(configDir: string, internalDefaultModel = 'internal-balanced') {
  mkdirSync(configDir, { recursive: true })
  writeFileSync(join(configDir, 'config.jsonc'), JSON.stringify({
    providers: {
      available: ['acme-gateway', 'internal-gateway'],
      defaultProvider: 'acme-gateway',
      defaultModel: 'fallback-large',
      descriptors: {
        'acme-gateway': {
          runtime: 'builtin',
          name: 'Acme Gateway',
          description: 'Acme model gateway',
          defaultModel: 'acme-large',
          credentials: [],
          models: [
            { id: 'fallback-large', name: 'Fallback Large' },
            { id: 'acme-large', name: 'Acme Large' },
          ],
        },
        'internal-gateway': {
          runtime: 'builtin',
          name: 'Internal Gateway',
          description: 'Internal model gateway',
          defaultModel: internalDefaultModel,
          smallModel: 'internal-fast',
          credentials: [],
          models: [
            { id: 'internal-fast', name: 'Internal Fast' },
            { id: 'internal-balanced', name: 'Internal Balanced' },
          ],
        },
      },
    },
  }))
}

function writeCredentialDescriptorConfig(configDir: string) {
  mkdirSync(configDir, { recursive: true })
  writeFileSync(join(configDir, 'config.jsonc'), JSON.stringify({
    providers: {
      available: ['acme'],
      defaultProvider: 'acme',
      defaultModel: 'acme/model',
      descriptors: {
        acme: {
          runtime: 'builtin',
          name: 'Acme',
          description: 'Acme provider',
          defaultModel: 'acme/model',
          credentials: [
            { key: 'apiKey', label: 'API key', description: 'Secret API key', secret: true },
            { key: 'projectId', label: 'Project', description: 'Visible project id', secret: false },
          ],
          models: [{ id: 'acme/model', name: 'Acme Model' }],
        },
      },
    },
    mcps: [{
      name: 'github',
      type: 'remote',
      description: 'GitHub',
      authMode: 'api_token',
      url: 'https://mcp.example.test/github',
      credentials: [
        { key: 'token', label: 'Token', description: 'Secret token', secret: true },
        { key: 'host', label: 'Host', description: 'Visible host', secret: false },
      ],
    }],
  }))
}

async function importFreshSettingsModule(label: string) {
  return import(`../apps/desktop/src/main/settings.ts?${label}-${Date.now()}`)
}

test('native permission ask defaults initialize fresh profiles with toggles enabled', async () => {
  const tempRoot = testTempDir('opencowork-settings-ask-defaults-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeAskPermissionConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings } = await importFreshSettingsModule('fresh-ask-defaults')
    const settings = loadSettings()
    assert.equal(settings.bashPermission, 'ask')
    assert.equal(settings.fileWritePermission, 'ask')
    assert.equal(settings.enableBash, true)
    assert.equal(settings.enableFileWrite, true)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('default public config initializes native permission toggles enabled', async () => {
  const tempRoot = testTempDir('opencowork-settings-public-defaults-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeEmptyConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings } = await importFreshSettingsModule('fresh-public-defaults')
    const settings = loadSettings()
    assert.equal(settings.bashPermission, 'ask')
    assert.equal(settings.fileWritePermission, 'ask')
    assert.equal(settings.enableBash, true)
    assert.equal(settings.enableFileWrite, true)
    assert.equal(settings.runtimeConfigSource, 'app')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('saveSettings normalizes renderer updates before persistence', async () => {
  const tempRoot = testTempDir('opencowork-settings-normalize-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeEmptyConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, saveSettings } = await importFreshSettingsModule('normalize-updates')
    const before = loadSettings()
    saveSettings({
      enableBash: false,
      workflowQuietHoursStart: '99:99',
      providerCredentials: {
        openrouter: {
          apiKey: 'valid-key',
          oversized: 'x'.repeat(65 * 1024),
        },
      },
      runtimeConfigSource: 'machine',
      unexpectedTopLevel: 'should not persist',
    } as any)

    const after = loadSettings() as any
    assert.equal(after.bashPermission, 'deny')
    assert.equal(after.enableBash, false)
    assert.equal(after.workflowQuietHoursStart, before.workflowQuietHoursStart)
    assert.equal(after.providerCredentials.openrouter.apiKey, 'valid-key')
    assert.equal(after.providerCredentials.openrouter.oversized, undefined)
    assert.equal(after.runtimeConfigSource, 'machine')
    assert.equal(after.unexpectedTopLevel, undefined)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('saveSettings persists explicit native permission modes and clamps to downstream maximums', async () => {
  const tempRoot = testTempDir('opencowork-settings-permission-modes-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeAskPermissionConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, saveSettings } = await importFreshSettingsModule('permission-modes')
    saveSettings({
      bashPermission: 'allow',
      fileWritePermission: 'deny',
    })

    const after = loadSettings()
    assert.equal(after.bashPermission, 'ask')
    assert.equal(after.enableBash, true)
    assert.equal(after.fileWritePermission, 'deny')
    assert.equal(after.enableFileWrite, false)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('saveSettings records an explicit persisted schema version', async () => {
  const tempRoot = testTempDir('opencowork-settings-schema-version-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeEmptyConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, saveSettings, SETTINGS_SCHEMA_VERSION } = await importFreshSettingsModule('schema-version')
    assert.equal(loadSettings()._schemaVersion, SETTINGS_SCHEMA_VERSION)
    saveSettings({ enableBash: false })
    const persisted = JSON.parse(readFileSync(join(userDataDir, 'settings.json'), 'utf-8'))
    assert.equal(persisted._schemaVersion, SETTINGS_SCHEMA_VERSION)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('loadSettings rejects settings from a newer schema version', async () => {
  const tempRoot = testTempDir('opencowork-settings-future-schema-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeEmptyConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { SETTINGS_SCHEMA_VERSION } = await importFreshSettingsModule('future-schema-constant')
    writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
      _schemaVersion: SETTINGS_SCHEMA_VERSION + 1,
      selectedProviderId: 'openrouter',
      selectedModelId: 'openrouter/auto',
    }))
    const { loadSettings } = await importFreshSettingsModule('future-schema-load')
    assert.throws(
      () => loadSettings(),
      /newer than supported/,
    )
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('loadSettings migrates legacy encrypted development settings to plaintext', async () => {
  const tempRoot = testTempDir('opencowork-settings-legacy-encrypted-dev-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeEmptyConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  const encryptedSettings = {
    selectedProviderId: 'openrouter',
    selectedModelId: 'openrouter/auto',
    providerCredentials: {
      openrouter: {
        apiKey: 'provider-secret',
      },
    },
  }
  writeFileSync(join(userDataDir, 'settings.enc'), `sealed:${JSON.stringify(encryptedSettings)}`)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const settingsModule = await importFreshSettingsModule('legacy-encrypted-dev-settings')
    settingsModule.setSettingsSecretStorageForTests({
      mode: 'plaintext',
      encryptString: (value: string) => Buffer.from(`sealed:${value}`),
      decryptString: (raw: Buffer) => raw.toString('utf-8').replace(/^sealed:/, ''),
    })

    const settings = settingsModule.loadSettings()
    assert.equal(settings.selectedProviderId, 'openrouter')
    assert.equal(settings.providerCredentials.openrouter.apiKey, 'provider-secret')

    const persisted = JSON.parse(readFileSync(join(userDataDir, 'settings.json'), 'utf-8'))
    assert.equal(persisted.providerCredentials.openrouter.apiKey, 'provider-secret')
    assert.equal(existsSync(join(userDataDir, 'settings.enc')), false)
    settingsModule.setSettingsSecretStorageForTests(null)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('credential reads return descriptor-aware masks while default effective settings can be masked', async () => {
  const tempRoot = testTempDir('opencowork-settings-scoped-credentials-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeCredentialDescriptorConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const {
      CREDENTIAL_MASK,
      getEffectiveSettings,
      getIntegrationCredentials,
      getProviderCredentials,
      maskEffectiveSettingsCredentials,
      saveSettings,
    } = await importFreshSettingsModule('scoped-credentials')
      saveSettings({
        providerCredentials: {
          acme: { apiKey: 'provider-secret', projectId: 'project-visible' },
          databricks: { token: 'other-provider-secret' },
        },
        integrationCredentials: {
          github: { token: 'integration-secret', host: 'github.example.test' },
        },
      })

    const masked = maskEffectiveSettingsCredentials(getEffectiveSettings())
    assert.equal(masked.providerCredentials.acme.apiKey, CREDENTIAL_MASK)
    assert.equal(masked.providerCredentials.acme.projectId, CREDENTIAL_MASK)
    assert.equal(masked.integrationCredentials.github.token, CREDENTIAL_MASK)
    assert.equal(masked.integrationCredentials.github.host, CREDENTIAL_MASK)
    assert.deepEqual(getProviderCredentials('acme'), {
      apiKey: CREDENTIAL_MASK,
      projectId: 'project-visible',
    })
    assert.deepEqual(getIntegrationCredentials('github'), {
      token: CREDENTIAL_MASK,
      host: 'github.example.test',
    })
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('legacy settings without native toggles inherit downstream ask defaults', async () => {
  const tempRoot = testTempDir('opencowork-settings-legacy-ask-defaults-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeAskPermissionConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'openrouter',
    selectedModelId: 'openrouter/auto',
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings } = await importFreshSettingsModule('legacy-ask-defaults')
    const settings = loadSettings()
    assert.equal(settings.bashPermission, 'ask')
    assert.equal(settings.fileWritePermission, 'ask')
    assert.equal(settings.enableBash, true)
    assert.equal(settings.enableFileWrite, true)
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('fresh settings initialize to the default provider local default model', async () => {
  const tempRoot = testTempDir('opencowork-settings-provider-default-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir)
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('fresh-provider-default')
    const settings = loadSettings()
    const effective = getEffectiveSettings(settings)
    assert.equal(settings.selectedProviderId, 'acme-gateway')
    assert.equal(settings.selectedModelId, 'acme-large')
    assert.equal(effective.effectiveProviderId, 'acme-gateway')
    assert.equal(effective.effectiveModel, 'acme-large')
    assert.equal(effective.effectiveSmallModel, 'acme-large')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('effective settings use a selected provider local default when the saved model belongs to another provider', async () => {
  const tempRoot = testTempDir('opencowork-settings-provider-switch-default-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'internal-gateway',
    selectedModelId: 'acme-large',
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('provider-switch-default')
    const effective = getEffectiveSettings(loadSettings())
    assert.equal(effective.effectiveProviderId, 'internal-gateway')
    assert.equal(effective.effectiveModel, 'internal-balanced')
    assert.equal(effective.effectiveSmallModel, 'internal-fast')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('effective settings accept provider-prefixed model ids for configured provider catalogs', async () => {
  const tempRoot = testTempDir('opencowork-settings-prefixed-provider-model-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'internal-gateway',
    selectedModelId: 'internal-gateway/internal-fast',
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('prefixed-provider-model')
    const effective = getEffectiveSettings(loadSettings())
    assert.equal(effective.effectiveProviderId, 'internal-gateway')
    assert.equal(effective.effectiveModel, 'internal-fast')
    assert.equal(effective.effectiveSmallModel, 'internal-fast')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('effective settings accept an explicit provider-prefixed small model', async () => {
  const tempRoot = testTempDir('opencowork-settings-small-model-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'internal-gateway',
    selectedModelId: 'internal-balanced',
    selectedSmallModelId: 'internal-gateway/internal-fast',
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('explicit-small-model')
    const effective = getEffectiveSettings(loadSettings())
    assert.equal(effective.effectiveProviderId, 'internal-gateway')
    assert.equal(effective.effectiveModel, 'internal-balanced')
    assert.equal(effective.effectiveSmallModel, 'internal-fast')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('effective settings let small model explicitly follow the selected main model', async () => {
  const tempRoot = testTempDir('opencowork-settings-small-model-main-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir)
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'internal-gateway',
    selectedModelId: 'internal-balanced',
    selectedSmallModelId: SMALL_MODEL_USE_MAIN,
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('small-model-main')
    const effective = getEffectiveSettings(loadSettings())
    assert.equal(effective.effectiveProviderId, 'internal-gateway')
    assert.equal(effective.effectiveModel, 'internal-balanced')
    assert.equal(effective.effectiveSmallModel, 'internal-balanced')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})

test('effective settings fall back to the first provider model when the provider local default is unavailable', async () => {
  const tempRoot = testTempDir('opencowork-settings-provider-default-missing-')
  const configDir = join(tempRoot, 'downstream')
  const userDataDir = join(tempRoot, 'user-data')
  const previousConfigDir = process.env.OPEN_COWORK_CONFIG_DIR
  const previousUserDataDir = process.env.OPEN_COWORK_USER_DATA_DIR

  writeProviderDefaultConfig(configDir, 'missing-model')
  mkdirSync(userDataDir, { recursive: true })
  writeFileSync(join(userDataDir, 'settings.json'), JSON.stringify({
    selectedProviderId: 'internal-gateway',
    selectedModelId: 'acme-large',
  }))
  process.env.OPEN_COWORK_CONFIG_DIR = configDir
  process.env.OPEN_COWORK_USER_DATA_DIR = userDataDir
  clearConfigCaches()

  try {
    const { loadSettings, getEffectiveSettings } = await importFreshSettingsModule('provider-default-missing')
    const effective = getEffectiveSettings(loadSettings())
    assert.equal(effective.effectiveProviderId, 'internal-gateway')
    assert.equal(effective.effectiveModel, 'internal-fast')
  } finally {
    if (previousConfigDir === undefined) delete process.env.OPEN_COWORK_CONFIG_DIR
    else process.env.OPEN_COWORK_CONFIG_DIR = previousConfigDir
    if (previousUserDataDir === undefined) delete process.env.OPEN_COWORK_USER_DATA_DIR
    else process.env.OPEN_COWORK_USER_DATA_DIR = previousUserDataDir
    clearConfigCaches()
    rmSync(tempRoot, { recursive: true, force: true })
  }
})
