/**
 * Live Agent Tests (requires extension to be running)
 *
 * These tests exercise legacy native-host backed utility flows.
 * Run with: npx tsx test/test-live.ts
 *
 * Prerequisites:
 * 1. Chrome extension installed and configured with API key
 * 2. Native host installed: cd native-host && ./install.sh
 * 3. Extension running (Chrome open)
 */

import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { fileURLToPath } from 'url';
import { spawn } from 'child_process';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// ============================================
// LOGGER
// ============================================

const LOG_DIR = path.join(__dirname, 'logs');
const LOG_FILE = path.join(LOG_DIR, `live-test-${new Date().toISOString().replace(/[:.]/g, '-')}.log`);

if (!fs.existsSync(LOG_DIR)) {
  fs.mkdirSync(LOG_DIR, { recursive: true });
}

function log(level: 'INFO' | 'PASS' | 'FAIL' | 'WARN' | 'DEBUG' | 'LLM', message: string, data?: any) {
  const timestamp = new Date().toISOString();
  const emoji = { INFO: '📋', PASS: '✅', FAIL: '❌', WARN: '⚠️', DEBUG: '🔍', LLM: '🤖' }[level];

  const logLine = `[${timestamp}] ${emoji} ${level}: ${message}`;
  const dataLine = data ? `\n    ${JSON.stringify(data, null, 2).split('\n').join('\n    ')}` : '';

  const colors: Record<string, string> = {
    INFO: '\x1b[36m', PASS: '\x1b[32m', FAIL: '\x1b[31m',
    WARN: '\x1b[33m', DEBUG: '\x1b[90m', LLM: '\x1b[35m'
  };
  console.log(`${colors[level]}${logLine}\x1b[0m${dataLine}`);
  fs.appendFileSync(LOG_FILE, logLine + dataLine + '\n');
}

function logSection(title: string) {
  const line = '═'.repeat(60);
  const msg = `\n${line}\n${title}\n${line}`;
  console.log(`\x1b[1m${msg}\x1b[0m`);
  fs.appendFileSync(LOG_FILE, msg + '\n');
}

// ============================================
// NATIVE HOST COMMUNICATION
// ============================================

/**
 * Find the native host executable
 */
function findNativeHost(): string | null {
  // Check native-host directory
  const localPath = path.join(__dirname, '..', '..', 'native-host', 'native-bridge.cjs');
  if (fs.existsSync(localPath)) {
    return localPath;
  }

  // Check installed manifest
  const manifestPath = path.join(
    os.homedir(),
    'Library', 'Application Support', 'Google', 'Chrome',
    'NativeMessagingHosts', 'com.hanzi_browse.oauth_host.json'
  );

  if (fs.existsSync(manifestPath)) {
    try {
      const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
      if (fs.existsSync(manifest.path)) {
        return manifest.path;
      }
    } catch {
      // Ignore
    }
  }

  return null;
}

/**
 * Send message to native host and get response
 */
async function sendToNativeHost(nativeHostPath: string, message: any): Promise<any> {
  return new Promise((resolve, reject) => {
    const proc = spawn('node', [nativeHostPath], {
      stdio: ['pipe', 'pipe', 'pipe'],
    });

    let stdout = Buffer.alloc(0);
    let stderr = '';

    proc.stdout.on('data', (data: Buffer) => {
      stdout = Buffer.concat([stdout, data]);
    });

    proc.stderr.on('data', (data: Buffer) => {
      stderr += data.toString();
    });

    proc.on('close', (code) => {
      if (stderr) {
        log('DEBUG', 'Native host stderr', { stderr: stderr.substring(0, 500) });
      }

      if (stdout.length >= 4) {
        // Native messaging format: 4-byte length prefix + JSON
        const length = stdout.readUInt32LE(0);
        const jsonStr = stdout.slice(4, 4 + length).toString('utf8');
        try {
          resolve(JSON.parse(jsonStr));
        } catch {
          resolve({ raw: jsonStr });
        }
      } else {
        resolve(null);
      }
    });

    proc.on('error', reject);

    // Send message in native messaging format
    const msgStr = JSON.stringify(message);
    const msgBuf = Buffer.from(msgStr, 'utf8');
    const lenBuf = Buffer.alloc(4);
    lenBuf.writeUInt32LE(msgBuf.length, 0);

    proc.stdin.write(lenBuf);
    proc.stdin.write(msgBuf);
    proc.stdin.end();

    // Timeout
    setTimeout(() => {
      proc.kill();
      reject(new Error('Native host timeout'));
    }, 10000);
  });
}

// ============================================
// TESTS
// ============================================

async function testNativeHostConnection(): Promise<boolean> {
  logSection('TEST: Native Host Connection');

  const nativeHostPath = findNativeHost();
  if (!nativeHostPath) {
    log('FAIL', 'Native host not found. Run: cd native-host && ./install.sh');
    return false;
  }

  log('INFO', `Found native host at: ${nativeHostPath}`);

  try {
    log('INFO', 'Sending ping to native host...');
    const response = await sendToNativeHost(nativeHostPath, { type: 'ping' });

    log('DEBUG', 'Ping response', response);

    if (response?.type === 'pong') {
      log('PASS', 'Native host is responding');
      return true;
    } else {
      log('FAIL', 'Unexpected response from native host');
      return false;
    }
  } catch (error: any) {
    log('FAIL', 'Failed to communicate with native host', { error: error.message });
    return false;
  }
}

async function testLLMThroughExtension(): Promise<boolean> {
  logSection('TEST: LLM Request Through Extension');
  log('WARN', 'Skipped: this legacy test depended on native-host file queueing, which is no longer used for MCP task traffic.');
  log('INFO', 'Use relay-backed MCP integration tests instead.');
  return true;
}

async function testPlanningAgentWithLLM(): Promise<boolean> {
  logSection('TEST: Planning Agent with LLM');

  // This test requires the full MCP server to be running
  // For now, we'll skip this and note it as a TODO

  log('INFO', 'This test requires the MCP server to be running.');
  log('INFO', 'To test: Start the MCP server and use browser_start tool with a complex task.');
  log('INFO', 'Check the logs for "[PlanningAgent] LLM analysis:" entries.');
  log('WARN', 'Skipping automated live test - manual verification needed.');

  return true; // Skip for now
}

// ============================================
// MAIN
// ============================================

async function runLiveTests() {
  console.log('\n');
  logSection('🔴 LIVE AGENT TESTS');
  log('INFO', `Log file: ${LOG_FILE}`);
  log('WARN', 'These tests require the Chrome extension to be running!');

  const results: { name: string; passed: boolean }[] = [];

  results.push({ name: 'Native Host Connection', passed: await testNativeHostConnection() });
  results.push({ name: 'LLM Through Extension', passed: await testLLMThroughExtension() });
  results.push({ name: 'Planning Agent with LLM', passed: await testPlanningAgentWithLLM() });

  // Summary
  logSection('📊 LIVE TEST SUMMARY');

  const passed = results.filter(r => r.passed).length;
  const total = results.length;

  for (const result of results) {
    log(result.passed ? 'PASS' : 'FAIL', result.name);
  }

  console.log('\n');
  if (passed === total) {
    log('PASS', `All ${total} live tests passed!`);
  } else {
    log('WARN', `${passed}/${total} live tests passed`);
  }

  log('INFO', `Full logs saved to: ${LOG_FILE}`);
}

runLiveTests().catch(err => {
  log('FAIL', 'Test runner crashed', { error: err.message, stack: err.stack });
  process.exit(1);
});
