import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { loadConfig, setupConfig, RC_FILE } from '../src/config';
import { writeFileSync, unlinkSync, existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { execSync } from 'child_process';

// Mock execSync
vi.mock('child_process', () => ({
  execSync: vi.fn()
}));

const RC_PATH = join(homedir(), RC_FILE);

describe('Config', () => {
  let originalRcContent: string | null = null;
  let originalEnv: NodeJS.ProcessEnv;

  beforeEach(() => {
    // Backup environment
    originalEnv = { ...process.env };

    // Clear environment variables we're testing
    delete process.env.ANTHROPIC_API_KEY;
    delete process.env.OPENAI_API_KEY;
    delete process.env.DEFAULT_MODEL;

    // Backup existing config if it exists
    if (existsSync(RC_PATH)) {
      originalRcContent = readFileSync(RC_PATH, 'utf-8');
      unlinkSync(RC_PATH); // Remove the file for clean tests
    }
    // Reset execSync mock
    vi.mocked(execSync).mockReset();
  });

  afterEach(() => {
    // Restore environment
    process.env = originalEnv;

    // Restore original config or remove test config
    if (originalRcContent) {
      writeFileSync(RC_PATH, originalRcContent);
    } else if (existsSync(RC_PATH)) {
      unlinkSync(RC_PATH);
    }
  });

  it('should load config from environment variables', () => {
    // Set environment variables
    process.env.ANTHROPIC_API_KEY = 'test-anthropic-key';
    process.env.OPENAI_API_KEY = 'test-openai-key';
    process.env.DEFAULT_MODEL = 'test-model';

    // Debug: Print environment variables
    console.log('Environment variables before loadConfig:');
    console.log('ANTHROPIC_API_KEY:', process.env.ANTHROPIC_API_KEY);
    console.log('OPENAI_API_KEY:', process.env.OPENAI_API_KEY);
    console.log('DEFAULT_MODEL:', process.env.DEFAULT_MODEL);

    const config = loadConfig();

    // Debug: Print loaded config
    console.log('Loaded config:');
    console.log('config.anthropicApiKey:', config.anthropicApiKey);
    console.log('config.openaiApiKey:', config.openaiApiKey);
    console.log('config.defaultModel:', config.defaultModel);

    expect(config.anthropicApiKey).toBe('test-anthropic-key');
    expect(config.openaiApiKey).toBe('test-openai-key');
    expect(config.defaultModel).toBe('test-model');
  });

  it('should load config from rc file', () => {
    const testConfig = {
      anthropicApiKey: 'test-anthropic-key',
      openaiApiKey: 'test-openai-key',
      defaultModel: 'test-model'
    };
    writeFileSync(RC_PATH, JSON.stringify(testConfig));

    const config = loadConfig();
    expect(config.anthropicApiKey).toBe('test-anthropic-key');
    expect(config.openaiApiKey).toBe('test-openai-key');
    expect(config.defaultModel).toBe('test-model');
  });

  it('should resolve 1Password secret references', () => {
    // Mock 1Password CLI responses
    vi.mocked(execSync)
      .mockReturnValueOnce('test-anthropic-key')
      .mockReturnValueOnce('test-openai-key');

    const testConfig = {
      anthropicApiKey: 'op://vault/anthropic/api-key',
      openaiApiKey: 'op://vault/openai/api-key',
      defaultModel: 'test-model'
    };
    writeFileSync(RC_PATH, JSON.stringify(testConfig));

    const config = loadConfig();
    expect(config.anthropicApiKey).toBe('test-anthropic-key');
    expect(config.openaiApiKey).toBe('test-openai-key');
    expect(config.defaultModel).toBe('test-model');

    // Verify 1Password CLI was called correctly
    expect(execSync).toHaveBeenCalledWith('op read "op://vault/anthropic/api-key"', { encoding: 'utf-8' });
    expect(execSync).toHaveBeenCalledWith('op read "op://vault/openai/api-key"', { encoding: 'utf-8' });
  });

  it('should handle 1Password CLI errors gracefully', () => {
    // Mock 1Password CLI error
    vi.mocked(execSync).mockImplementation(() => {
      const error = new Error('1Password CLI not found');
      error.message = '1Password CLI not found';
      throw error;
    });

    const testConfig = {
      anthropicApiKey: 'op://vault/anthropic/api-key'
    };
    writeFileSync(RC_PATH, JSON.stringify(testConfig));

    expect(() => loadConfig()).toThrow('Failed to resolve 1Password secret reference');
  });

  it('should override rc file with passed options', () => {
    const testConfig = {
      anthropicApiKey: 'test-anthropic-key',
      openaiApiKey: 'test-openai-key',
      defaultModel: 'test-model'
    };
    writeFileSync(RC_PATH, JSON.stringify(testConfig));

    const config = loadConfig({
      anthropicApiKey: 'override-key'
    });
    expect(config.anthropicApiKey).toBe('override-key');
    expect(config.openaiApiKey).toBe('test-openai-key');
    expect(config.defaultModel).toBe('test-model');
  });

  it('should handle missing rc file gracefully', () => {
    if (existsSync(RC_PATH)) {
      unlinkSync(RC_PATH);
    }

    expect(() => loadConfig()).not.toThrow();
  });
}); 