import { describe, it, expect } from 'vitest';
import { extractCodexConfigEnvKeys, filterCodexEnv } from '../utils/codex-client';
import { SENSITIVE_LOG_PATTERN, ALLOWED_MEDIA_TYPES, resolveMediaExtension } from '../api/ai/chat';

// ---------------------------------------------------------------------------
// 1. Codex client env allowlist
// ---------------------------------------------------------------------------
describe('codex client env allowlist', () => {
  it('should strip dangerous env vars', () => {
    const env = {
      PATH: '/usr/bin',
      HOME: '/home/user',
      AWS_SECRET_KEY: 'supersecret',
      DATABASE_URL: 'postgres://...',
      ANTHROPIC_API_KEY: 'sk-ant-xxx',
      GITHUB_TOKEN: 'ghp_xxx',
    };
    const filtered = filterCodexEnv(env);
    expect(filtered).not.toHaveProperty('AWS_SECRET_KEY');
    expect(filtered).not.toHaveProperty('DATABASE_URL');
    expect(filtered).not.toHaveProperty('ANTHROPIC_API_KEY');
    expect(filtered).not.toHaveProperty('GITHUB_TOKEN');
  });

  it('should keep PATH, HOME, and shell vars', () => {
    const env = {
      PATH: '/usr/bin',
      HOME: '/home/user',
      TERM: 'xterm-256color',
      LANG: 'en_US.UTF-8',
      SHELL: '/bin/zsh',
      TMPDIR: '/tmp',
    };
    const filtered = filterCodexEnv(env);
    expect(filtered.PATH).toBe('/usr/bin');
    expect(filtered.HOME).toBe('/home/user');
    expect(filtered.TERM).toBe('xterm-256color');
    expect(filtered.LANG).toBe('en_US.UTF-8');
    expect(filtered.SHELL).toBe('/bin/zsh');
    expect(filtered.TMPDIR).toBe('/tmp');
  });

  it('should keep OPENAI_* and CODEX_* vars', () => {
    const env = {
      PATH: '/usr/bin',
      HOME: '/home/user',
      OPENAI_API_KEY: 'sk-openai-xxx',
      OPENAI_ORG_ID: 'org-xxx',
      CODEX_TOKEN: 'codex-xxx',
      CODEX_SANDBOX: 'read-only',
    };
    const filtered = filterCodexEnv(env);
    expect(filtered.OPENAI_API_KEY).toBe('sk-openai-xxx');
    expect(filtered.OPENAI_ORG_ID).toBe('org-xxx');
    expect(filtered.CODEX_TOKEN).toBe('codex-xxx');
    expect(filtered.CODEX_SANDBOX).toBe('read-only');
  });

  it('should keep custom provider env keys declared in codex config', () => {
    const env = {
      PATH: '/usr/bin',
      HOME: '/home/user',
      agw_CODE: 'sk-agw-xxx',
      PACKYCODE: 'sk-packy-xxx',
      OTHER_SECRET: 'bad',
    };
    const extraAllowed = extractCodexConfigEnvKeys(`
[model_providers.agw]
env_key = "agw_CODE"

[model_providers.packycode]
env_key = "PACKYCODE"
`);
    const filtered = filterCodexEnv(env, extraAllowed);

    expect(filtered.agw_CODE).toBe('sk-agw-xxx');
    expect(filtered.PACKYCODE).toBe('sk-packy-xxx');
    expect(filtered).not.toHaveProperty('OTHER_SECRET');
  });

  it('should not leak vars with similar prefixes', () => {
    const env = {
      PATH: '/usr/bin',
      HOME: '/home/user',
      OPENAI_API_KEY: 'ok',
      OPENAI_COMPAT: 'ok',
      OPEN_SECRET: 'bad',
      CODEX_MODE: 'ok',
      CODE_SECRET: 'bad',
    };
    const filtered = filterCodexEnv(env);
    expect(filtered).not.toHaveProperty('OPEN_SECRET');
    expect(filtered).not.toHaveProperty('CODE_SECRET');
    expect(filtered.OPENAI_API_KEY).toBe('ok');
    expect(filtered.CODEX_MODE).toBe('ok');
  });
});

// ---------------------------------------------------------------------------
// 2. Debug tail sanitization
// ---------------------------------------------------------------------------
describe('debug tail sanitization', () => {
  it('should match ANTHROPIC_API_KEY leak', () => {
    expect(SENSITIVE_LOG_PATTERN.test('ANTHROPIC_API_KEY=sk-ant-abc123')).toBe(true);
  });

  it('should match Authorization Bearer header', () => {
    expect(SENSITIVE_LOG_PATTERN.test('Authorization: Bearer token123')).toBe(true);
    expect(SENSITIVE_LOG_PATTERN.test('authorization:  Bearer xyz')).toBe(true);
  });

  it('should match api_key and api-key patterns', () => {
    expect(SENSITIVE_LOG_PATTERN.test('api_key=secret')).toBe(true);
    expect(SENSITIVE_LOG_PATTERN.test('api-key: secret')).toBe(true);
    expect(SENSITIVE_LOG_PATTERN.test('apikey=secret')).toBe(true);
  });

  it('should NOT match normal log lines', () => {
    expect(SENSITIVE_LOG_PATTERN.test('Using API endpoint https://api.anthropic.com')).toBe(false);
    expect(SENSITIVE_LOG_PATTERN.test('Model: claude-sonnet-4-5-20250929')).toBe(false);
    expect(SENSITIVE_LOG_PATTERN.test('Request completed in 1200ms')).toBe(false);
    expect(SENSITIVE_LOG_PATTERN.test('Connecting to upstream server...')).toBe(false);
  });
});

// ---------------------------------------------------------------------------
// 3. Media type allowlist
// ---------------------------------------------------------------------------
describe('media type allowlist', () => {
  it('should allow standard image types', () => {
    expect(ALLOWED_MEDIA_TYPES.has('image/png')).toBe(true);
    expect(ALLOWED_MEDIA_TYPES.has('image/jpeg')).toBe(true);
    expect(ALLOWED_MEDIA_TYPES.has('image/gif')).toBe(true);
    expect(ALLOWED_MEDIA_TYPES.has('image/webp')).toBe(true);
  });

  it('should reject non-image types', () => {
    expect(ALLOWED_MEDIA_TYPES.has('image/svg+xml')).toBe(false);
    expect(ALLOWED_MEDIA_TYPES.has('application/pdf')).toBe(false);
    expect(ALLOWED_MEDIA_TYPES.has('text/html')).toBe(false);
  });

  it('should resolve extensions correctly', () => {
    expect(resolveMediaExtension('image/png')).toBe('png');
    expect(resolveMediaExtension('image/jpeg')).toBe('jpeg');
    expect(resolveMediaExtension('image/gif')).toBe('gif');
    expect(resolveMediaExtension('image/webp')).toBe('webp');
  });

  it('should fall back to png for disallowed types', () => {
    expect(resolveMediaExtension('image/x-sh')).toBe('png');
    expect(resolveMediaExtension('image/svg+xml')).toBe('png');
    expect(resolveMediaExtension('application/pdf')).toBe('png');
    expect(resolveMediaExtension('text/html')).toBe('png');
    expect(resolveMediaExtension('')).toBe('png');
  });
});
