import { describe, expect, test } from 'bun:test'
import { mkdtempSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import {
  TURINGP_BASE_URL,
  TURINGP_ENV_FILE,
  TURINGP_MODEL,
  TURING_CLAUDE_MODEL,
  TURING_GROK_BASE_URL,
  TURING_GROK_MODEL,
  TURING_GROK_IMAGE_MODEL,
  TURING_OPENAI_IMAGE_MODEL,
  TURING_OPENAI_MODEL,
  buildTuringClaudeArgv,
  buildTuringClaudeEnv,
  buildTuringGrokArgv,
  buildTuringGrokEnv,
  buildTuringGrokSettings,
  buildTuringOpenAIArgv,
  buildTuringOpenAIEnv,
  buildTuringOpenAISettings,
  buildTuringpArgv,
  buildTuringpEnv,
  parseSimpleEnvFile,
} from './presetLauncher.js'

function extractInlineSettings(argv: string[]) {
  const settingsIndex = argv.indexOf('--settings')
  if (settingsIndex === -1) {
    return null
  }
  return JSON.parse(argv[settingsIndex + 1]!)
}

function createTuringConfigDir(config: Record<string, unknown> = {}) {
  void config
  const dir = mkdtempSync(join(tmpdir(), 'turing-config-'))
  return dir
}

describe('provider 预设入口', () => {
  test('gemini 普通调用会强制落到 gemini-3.1-flash-lite-preview', () => {
    const argv = buildTuringpArgv(
      ['-p', 'hello'],
      {
        TURING_CONFIG_DIR: createTuringConfigDir(),
      },
      {},
    )

    expect(argv.slice(0, 6)).toEqual([
      '-p',
      'hello',
      '--model',
      TURINGP_MODEL,
      '--setting-sources',
      'user',
    ])
    expect(extractInlineSettings(argv)).toEqual({
      model: TURINGP_MODEL,
      env: {
        TURING_DISABLE_GLOBAL_CONFIG: '1',
        TURING_PROVIDER_PRESET: 'gemini',
        CLAUDE_CODE_USE_GEMINI: '1',
        CLAUDE_CODE_USE_OPENAI_RESPONSES: '',
        CLAUDE_CODE_USE_BEDROCK: '',
        CLAUDE_CODE_USE_VERTEX: '',
        CLAUDE_CODE_USE_FOUNDRY: '',
        GEMINI_MODEL: TURINGP_MODEL,
        GEMINI_BASE_URL: TURINGP_BASE_URL,
      },
    })
  })

  test('gemini 已有 --model 时会剥离旧值并改成固定模型', () => {
    expect(
      buildTuringpArgv(
        [
          '-p',
          'hello',
          '--model',
          'gemini-2.5-flash',
        ],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
        {},
      ).slice(0, 6),
    ).toEqual([
      '-p',
      'hello',
      '--model',
      TURINGP_MODEL,
      '--setting-sources',
      'user',
    ])

    expect(
      buildTuringpArgv(
        [
          '-p',
          'hello',
          '--model=gemini-2.5-flash',
        ],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
        {},
      ).slice(0, 6),
    ).toEqual([
      '-p',
      'hello',
      '--model',
      TURINGP_MODEL,
      '--setting-sources',
      'user',
    ])
  })

  test('帮助、版本与子命令透传，不额外追加模型参数', () => {
    const baseEnv = { TURING_CONFIG_DIR: createTuringConfigDir() }
    expect(buildTuringpArgv(['--help'], baseEnv)).toEqual(['--help'])
    expect(buildTuringpArgv(['-v'], baseEnv)).toEqual(['-v'])
    expect(buildTuringpArgv(['auth', 'login'], baseEnv)).toEqual(['auth', 'login'])
  })

  test('gemini 与 claude 默认忽略项目级 settings，避免默认 openai 污染 alias', () => {
    const baseEnv = { TURING_CONFIG_DIR: createTuringConfigDir() }
    const geminiArgv = buildTuringpArgv(['-p', 'hello'], baseEnv, {})
    expect(geminiArgv.slice(0, 6)).toEqual([
      '-p',
      'hello',
      '--model',
      TURINGP_MODEL,
      '--setting-sources',
      'user',
    ])
    expect(extractInlineSettings(geminiArgv)?.env.CLAUDE_CODE_USE_OPENAI_RESPONSES).toBe('')

    const claudeArgv = buildTuringClaudeArgv(['-p', 'hello'], baseEnv)
    expect(claudeArgv.slice(0, 6)).toEqual([
      '-p',
      'hello',
      '--model',
      TURING_CLAUDE_MODEL,
      '--setting-sources',
      'user',
    ])
    expect(extractInlineSettings(claudeArgv)).toEqual({
      model: TURING_CLAUDE_MODEL,
      env: {
        TURING_DISABLE_GLOBAL_CONFIG: '1',
        TURING_PROVIDER_PRESET: 'claude',
        CLAUDE_CODE_USE_GEMINI: '',
        CLAUDE_CODE_USE_OPENAI_RESPONSES: '',
        CLAUDE_CODE_USE_BEDROCK: '',
        CLAUDE_CODE_USE_VERTEX: '',
        CLAUDE_CODE_USE_FOUNDRY: '',
        OPENAI_BASE_URL: '',
        OPENAI_API_KEY: '',
        OPENAI_MODEL: '',
        GEMINI_BASE_URL: '',
        GEMINI_API_KEY: '',
        GEMINI_MODEL: '',
        GOOGLE_GEMINI_BASE_URL: '',
        GOOGLE_GEMINI_API_KEY: '',
        ANTHROPIC_BASE_URL: 'https://sub-lb.tap365.org',
        ANTHROPIC_MODEL: TURING_CLAUDE_MODEL,
      },
    })
  })

  test('显式传入 --setting-sources 时保留调用者选择', () => {
    expect(
      buildTuringpArgv(
        ['-p', 'hello', '--setting-sources', 'user,project'],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
        {},
      ).slice(0, 6),
    ).toEqual(['-p', 'hello', '--setting-sources', 'user,project', '--model', TURINGP_MODEL])

    expect(
      buildTuringClaudeArgv(
        ['-p', 'hello', '--setting-sources=user,project'],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
      ).slice(0, 5),
    ).toEqual(['-p', 'hello', '--setting-sources=user,project', '--model', TURING_CLAUDE_MODEL])
  })

  test('显式传入 --settings 时保留调用者自定义 settings', () => {
    expect(
      buildTuringpArgv(
        ['-p', 'hello', '--settings', '{"model":"custom"}'],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
        {},
      ),
    ).toEqual([
      '-p',
      'hello',
      '--settings',
      '{"model":"custom"}',
      '--model',
      TURINGP_MODEL,
      '--setting-sources',
      'user',
    ])

    expect(
      buildTuringClaudeArgv(
        ['-p', 'hello', '--settings={"model":"custom"}'],
        { TURING_CONFIG_DIR: createTuringConfigDir() },
      ),
    ).toEqual([
      '-p',
      'hello',
      '--settings={"model":"custom"}',
      '--model',
      TURING_CLAUDE_MODEL,
      '--setting-sources',
      'user',
    ])
  })

  test('gemini 环境会强制切到 gemini 并清掉其他 provider 标记', () => {
    const env = buildTuringpEnv(
      {
        TURING_CONFIG_DIR: createTuringConfigDir(),
        CLAUDE_CODE_USE_BEDROCK: '1',
        CLAUDE_CODE_USE_OPENAI_RESPONSES: '1',
        FOO: 'bar',
      },
      {},
    )

    expect(env.CLAUDE_CODE_USE_GEMINI).toBe('1')
    expect(env.TURING_PROVIDER_PRESET).toBe('gemini')
    expect(env.GEMINI_MODEL).toBe(TURINGP_MODEL)
    expect(env.GEMINI_BASE_URL).toBe(TURINGP_BASE_URL)
    expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined()
    expect(env.CLAUDE_CODE_USE_OPENAI_RESPONSES).toBeUndefined()
    expect(env.FOO).toBe('bar')
  })

  test('turingp 默认不再读取 ~/.claude/turingp.env', () => {
    const claudeConfigDir = mkdtempSync(join(tmpdir(), 'turingp-env-'))
    writeFileSync(
      join(claudeConfigDir, TURINGP_ENV_FILE),
      [
        'export GEMINI_BASE_URL="https://api.zyai.online/v1"',
        'export GEMINI_API_KEY="gemini-file-key"',
      ].join('\n'),
      'utf8',
    )

    const env = buildTuringpEnv({
      TURING_CONFIG_DIR: createTuringConfigDir(),
      CLAUDE_CONFIG_DIR: claudeConfigDir,
    })

    expect(env.GEMINI_BASE_URL).toBe(TURINGP_BASE_URL)
    expect(env.GEMINI_API_KEY).toBeUndefined()
  })

  test('turingp 只从环境变量读取 key，不再默认读取 ~/.claude/turingp.env', () => {
    const claudeConfigDir = mkdtempSync(join(tmpdir(), 'turingp-env-'))
    writeFileSync(
      join(claudeConfigDir, TURINGP_ENV_FILE),
      [
        'export GEMINI_BASE_URL="https://api.zyai.online/v1"',
        'export GEMINI_API_KEY="gemini-file-key"',
      ].join('\n'),
      'utf8',
    )

    const env = buildTuringpEnv({
      TURING_CONFIG_DIR: createTuringConfigDir({
        GEMINI_API_KEY: 'gemini-config-key',
      }),
      CLAUDE_CONFIG_DIR: claudeConfigDir,
      GEMINI_BASE_URL: 'https://example.com/v1',
      GEMINI_API_KEY: 'gemini-shell-key',
    })

    expect(env.GEMINI_BASE_URL).toBe('https://example.com/v1')
    expect(env.GEMINI_API_KEY).toBe('gemini-shell-key')
  })

  test('openai alias 文本链路固定走 sub-lb，图片链路单独走 progpt', () => {
    const env = buildTuringOpenAIEnv({
      CLAUDE_CODE_USE_GEMINI: '1',
      GEMINI_MODEL: 'gemini-3.1-flash-lite-preview',
      OPENAI_API_KEY: 'openai-env-key',
    })

    expect(env.CLAUDE_CODE_USE_OPENAI_RESPONSES).toBe('1')
    expect(env.TURING_PROVIDER_PRESET).toBe('openai')
    expect(env.CLAUDE_CODE_USE_GEMINI).toBeUndefined()
    expect(env.GEMINI_MODEL).toBeUndefined()
    expect(env.OPENAI_BASE_URL).toBe('https://sub-lb.tap365.org/v1')
    expect(env.OPENAI_API_KEY).toBe('openai-env-key')
    expect(env.OPENAI_MODEL).toBe(TURING_OPENAI_MODEL)
    expect(env.TURING_IMAGE_BASE_URL).toBe('https://progpt.tap365.org/c2a-4a57f72b')
  })

  test('openai alias 会追加 inline settings，避免项目级 settings 覆盖默认 openai preset', () => {
    const baseEnv = {
      OPENAI_API_KEY: 'openai-env-key',
      OPENAI_BASE_URL: 'https://api.zyai.online/v1',
    }
    const argv = buildTuringOpenAIArgv(['-p', 'hello'], baseEnv)

    expect(argv.slice(0, 6)).toEqual([
      '-p',
      'hello',
      '--model',
      TURING_OPENAI_MODEL,
      '--setting-sources',
      'user',
    ])
    expect(extractInlineSettings(argv)).toEqual(buildTuringOpenAISettings(baseEnv))
  })

  test('openai alias 只从环境变量读取 key，且文本默认 base url 不再漂到 progpt', () => {
    const env = buildTuringOpenAIEnv({
      TURING_CONFIG_DIR: createTuringConfigDir({
        PROGPT_IMAGE_KEY: 'progpt-config-key',
      }),
      OPENAI_API_KEY: 'progpt-env-key',
    })

    expect(env.OPENAI_API_KEY).toBe('progpt-env-key')
    expect(env.OPENAI_BASE_URL).toBe('https://sub-lb.tap365.org/v1')
  })

  test('openai alias 在无显式 key 时会回退到内置默认 key', () => {
    const env = buildTuringOpenAIEnv({})

    expect(env.OPENAI_API_KEY).toBe(
      'sk-fb96b493ee4171ecffcfc01c202555c92f846116ee1f3fb134a6b5d87f9ff06e',
    )
    expect(env.TURING_IMAGE_API_KEY).toBe(
      'sk-fb96b493ee4171ecffcfc01c202555c92f846116ee1f3fb134a6b5d87f9ff06e',
    )
  })

  test('openai image 子命令不再注入 --setting-sources/--settings，且默认补图片模型', () => {
    const argv = buildTuringOpenAIArgv(['image', 'generate', '--output', '/tmp/a.png', 'hello'])

    expect(argv).toEqual([
      'image',
      'generate',
      '--model',
      TURING_OPENAI_IMAGE_MODEL,
      '--output',
      '/tmp/a.png',
      'hello',
    ])
  })

  test('openai image 子命令如果已显式传 --model，则保留调用者选择', () => {
    const argv = buildTuringOpenAIArgv(['image', 'edit', '--model', 'custom-image-model', '--image', '/tmp/a.png', 'hello'])

    expect(argv).toEqual([
      'image',
      'edit',
      '--model',
      'custom-image-model',
      '--image',
      '/tmp/a.png',
      'hello',
    ])
  })

  test('openai alias 会给图片链路注入独立图片环境变量', () => {
    const env = buildTuringOpenAIEnv({
      OPENAI_API_KEY: 'openai-env-key',
    })

    expect(env.TURING_IMAGE_BASE_URL).toBe('https://progpt.tap365.org/c2a-4a57f72b')
    expect(env.TURING_IMAGE_API_KEY).toBe('openai-env-key')
    expect(env.TURING_IMAGE_MODEL).toBe('gpt-image-1-mini')
  })

  test('openai inline settings 也会给图片链路注入独立图片环境变量', () => {
    const settings = buildTuringOpenAISettings({
      OPENAI_API_KEY: 'openai-env-key',
    })

    expect(settings?.env?.TURING_IMAGE_BASE_URL).toBe('https://progpt.tap365.org/c2a-4a57f72b')
    expect(settings?.env?.TURING_IMAGE_API_KEY).toBe('openai-env-key')
    expect(settings?.env?.TURING_IMAGE_MODEL).toBe('gpt-image-1-mini')
  })

  test('claude alias 会固定到 anthropic 原生 + claude-sonnet-4-6', () => {
    const env = buildTuringClaudeEnv({
      CLAUDE_CODE_USE_GEMINI: '1',
      ANTHROPIC_AUTH_TOKEN: 'anthropic-env-key',
    })

    expect(env.CLAUDE_CODE_USE_GEMINI).toBeUndefined()
    expect(env.CLAUDE_CODE_USE_OPENAI_RESPONSES).toBeUndefined()
    expect(env.TURING_PROVIDER_PRESET).toBe('claude')
    expect(env.OPENAI_BASE_URL).toBeUndefined()
    expect(env.OPENAI_API_KEY).toBeUndefined()
    expect(env.ANTHROPIC_BASE_URL).toBe('https://sub-lb.tap365.org')
    expect(env.ANTHROPIC_API_KEY).toBe('anthropic-env-key')
    expect(env.ANTHROPIC_AUTH_TOKEN).toBe('anthropic-env-key')
    expect(env.ANTHROPIC_MODEL).toBe(TURING_CLAUDE_MODEL)
  })

  test('claude image 子命令不再强注入文本模型，避免 image models 被错塞 --model', () => {
    const argv = buildTuringClaudeArgv(['image', 'models'])

    expect(argv).toEqual(['image', 'models'])
  })

  test('grok alias 会强制走 openai-compatible + grok74 默认模型', () => {
    const env = buildTuringGrokEnv({
      CLAUDE_CODE_USE_GEMINI: '1',
      GEMINI_MODEL: 'gemini-3.1-flash-lite-preview',
      GROK_API_KEY: 'grok-env-key',
    })

    expect(env.CLAUDE_CODE_USE_OPENAI_RESPONSES).toBe('1')
    expect(env.TURING_PROVIDER_PRESET).toBe('grok')
    expect(env.CLAUDE_CODE_USE_GEMINI).toBeUndefined()
    expect(env.GEMINI_MODEL).toBeUndefined()
    expect(env.OPENAI_BASE_URL).toBe(TURING_GROK_BASE_URL)
    expect(env.OPENAI_API_KEY).toBe('grok-env-key')
    expect(env.GROK_API_KEY).toBe('grok-env-key')
    expect(env.OPENAI_MODEL).toBe(TURING_GROK_MODEL)
  })

  test('grok alias 只从环境变量读取 key，不再默认读取 ~/.turing/config.json', () => {
    const env = buildTuringGrokEnv({
      TURING_CONFIG_DIR: createTuringConfigDir({
        TURING_KEY: 'openai-config-key',
      }),
      GROK_API_KEY: 'grok-env-key',
    })

    expect(env.OPENAI_API_KEY).toBe('grok-env-key')
    expect(env.GROK_API_KEY).toBe('grok-env-key')
    expect(env.OPENAI_BASE_URL).toBe(TURING_GROK_BASE_URL)
    expect(env.OPENAI_MODEL).toBe(TURING_GROK_MODEL)
  })

  test('grok alias 会追加 inline settings，避免项目级 settings 把 base url 覆盖回默认 openai', () => {
    const baseEnv = {
      TURING_CONFIG_DIR: createTuringConfigDir({
        GROK_API_KEY: 'grok-config-key',
      }),
      GROK_BASE_URL: 'http://127.0.0.1:18777/v1',
    }
    const argv = buildTuringGrokArgv(['-p', 'hello'], baseEnv)

    expect(argv.slice(0, 6)).toEqual([
      '-p',
      'hello',
      '--model',
      TURING_GROK_MODEL,
      '--setting-sources',
      'user',
    ])
    expect(extractInlineSettings(argv)).toEqual(buildTuringGrokSettings(baseEnv))
  })

  test('grok inline settings 会同时注入 GROK_API_KEY，避免运行时只认 grok preset 键时回退到 TURING_KEY', () => {
    const settings = buildTuringGrokSettings({
      GROK_API_KEY: 'grok-env-key',
    })

    expect(settings?.env?.GROK_API_KEY).toBe('grok-env-key')
    expect(settings?.env?.OPENAI_API_KEY).toBe('grok-env-key')
  })


  test('grok image 子命令不再注入 --setting-sources/--settings，且默认补 grok 图片模型', () => {
    const argv = buildTuringGrokArgv(['image', 'generate', '--output', '/tmp/a.png', 'hello'])

    expect(argv).toEqual(['image', 'generate', '--model', TURING_GROK_IMAGE_MODEL, '--output', '/tmp/a.png', 'hello'])
  })

  test('grok image 子命令如果已显式传 --model，则保留调用者选择', () => {
    const argv = buildTuringGrokArgv(['image', 'generate', '--model', 'custom-image-model', 'hello'])

    expect(argv).toEqual(['image', 'generate', '--model', 'custom-image-model', 'hello'])
  })

  test('grok alias 会给图片链路注入独立图片环境变量', () => {
    const env = buildTuringGrokEnv({
      GROK_API_KEY: 'grok-env-key',
    })

    expect(env.TURING_IMAGE_BASE_URL).toBe(TURING_GROK_BASE_URL)
    expect(env.TURING_IMAGE_API_KEY).toBe('grok-env-key')
    expect(env.TURING_IMAGE_MODEL).toBe(TURING_GROK_IMAGE_MODEL)
  })

  test('grok inline settings 也会给图片链路注入独立图片环境变量', () => {
    const settings = buildTuringGrokSettings({
      GROK_API_KEY: 'grok-env-key',
    })

    expect(settings?.env?.TURING_IMAGE_BASE_URL).toBe(TURING_GROK_BASE_URL)
    expect(settings?.env?.TURING_IMAGE_API_KEY).toBe('grok-env-key')
    expect(settings?.env?.TURING_IMAGE_MODEL).toBe(TURING_GROK_IMAGE_MODEL)
  })

  test('支持解析 export 与引号写法', () => {
    const parsed = parseSimpleEnvFile(`
      # comment
      export GEMINI_BASE_URL="https://api.zyai.online/v1"
      GEMINI_API_KEY='gemini-test-key'
    `)

    expect(parsed).toEqual({
      GEMINI_BASE_URL: 'https://api.zyai.online/v1',
      GEMINI_API_KEY: 'gemini-test-key',
    })
  })
})
