import { spawn } from 'child_process';
import { join } from 'path';
import { writeFileSync, unlinkSync, existsSync } from 'fs';
import { beforeEach, afterEach, describe, it, expect } from 'vitest';
import { vi } from 'vitest';

const CLI_PATH = join(__dirname, '../../bin/oneshot.ts');
const TEST_PROMPT = 'test-prompt.md';
const TEST_OUTPUT = 'test-output.md';
const TEST_SYSTEM = 'test-system.md';
const TEST_VARIATIONS_JSON = 'test-variations.json';
const TEST_VARIATIONS_YAML = 'test-variations.yaml';

// Mock environment variables
process.env.ANTHROPIC_API_KEY = 'test-anthropic-key';
process.env.OPENAI_API_KEY = 'test-openai-key';

describe('oneshot CLI', () => {
  beforeEach(() => {
    // Create test files
    writeFileSync(TEST_PROMPT, '# Test Prompt\n\nThis is a test prompt.');
    writeFileSync(TEST_SYSTEM, 'You are a helpful assistant.');
    writeFileSync(TEST_VARIATIONS_JSON, JSON.stringify(['Perspective 1', 'Perspective 2']));
    writeFileSync(TEST_VARIATIONS_YAML, 'architect: "Review as architect"\ndeveloper: "Review as developer"');
  });

  afterEach(() => {
    // Cleanup test files
    [TEST_PROMPT, TEST_OUTPUT, TEST_SYSTEM, TEST_VARIATIONS_JSON, TEST_VARIATIONS_YAML].forEach(file => {
      if (existsSync(file)) unlinkSync(file);
    });
  });

  it('should send a simple prompt to Claude', (done) => {
    const oneshot = spawn('ts-node', [CLI_PATH, 'claude-3', TEST_PROMPT]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support multiple models', (done) => {
    const oneshot = spawn('ts-node', [CLI_PATH, 'claude-3', 'gpt-4', TEST_PROMPT]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      expect(output).toContain('🤖 Sending prompt to gpt-4');
      done();
    });
  });

  it('should support inline system prompt', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--system',
      'You are a helpful assistant'
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support system prompts from file', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--system-file',
      TEST_SYSTEM
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support inline variations', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--variations',
      '["View 1", "View 2"]'
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support variations from JSON file', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--variations-file',
      TEST_VARIATIONS_JSON
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support variations from YAML file', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--variations-file',
      TEST_VARIATIONS_YAML
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support multiple iterations', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--iterations',
      '3'
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(output).toContain('🤖 Sending prompt to claude-3');
      done();
    });
  });

  it('should support custom output file', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '-o',
      TEST_OUTPUT
    ]);
    
    let output = '';
    oneshot.stdout.on('data', (data) => {
      output += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(0);
      expect(existsSync(TEST_OUTPUT)).toBe(true);
      expect(output).toContain('📝 Response written to');
      done();
    });
  });

  it('should handle missing prompt file error', (done) => {
    const oneshot = spawn('ts-node', [CLI_PATH, 'claude-3', 'nonexistent.md']);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(1);
      expect(stderr).toContain('ENOENT');
      done();
    });
  });

  it('should handle missing system file error', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--system-file',
      'nonexistent.md'
    ]);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(1);
      expect(stderr).toContain('ENOENT');
      done();
    });
  });

  it('should handle missing variations file error', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--variations-file',
      'nonexistent.yaml'
    ]);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(1);
      expect(stderr).toContain('ENOENT');
      done();
    });
  });

  it('should handle invalid JSON variations error', (done) => {
    const oneshot = spawn('ts-node', [
      CLI_PATH,
      'claude-3',
      TEST_PROMPT,
      '--variations',
      'invalid json'
    ]);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(1);
      expect(stderr).toContain('JSON');
      done();
    });
  });

  it('should handle missing API key error', (done) => {
    // Temporarily unset API key
    const oldKey = process.env.ANTHROPIC_API_KEY;
    delete process.env.ANTHROPIC_API_KEY;

    const oneshot = spawn('ts-node', [CLI_PATH, 'claude-3', TEST_PROMPT]);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      // Restore API key
      process.env.ANTHROPIC_API_KEY = oldKey;
      
      expect(code).toBe(1);
      expect(stderr).toContain('Anthropic API key is required');
      done();
    });
  });

  it('should handle unsupported model error', (done) => {
    const oneshot = spawn('ts-node', [CLI_PATH, 'unsupported-model', TEST_PROMPT]);
    
    let stderr = '';
    oneshot.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    oneshot.on('close', (code) => {
      expect(code).toBe(1);
      expect(stderr).toContain('Unsupported model');
      done();
    });
  });
}); 