#!/usr/bin/env node

/**
 * Mock Server Integration Test
 * 
 * Tests the mock server functionality to ensure all endpoints work correctly
 */

const http = require('http');

const MOCK_SERVER_URL = 'http://localhost:3002';
const TIMEOUT = 5000; // 5 seconds

function makeRequest(path, method = 'GET', body = null) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname: 'localhost',
      port: 3002,
      path: path,
      method: method,
      headers: {
        'Content-Type': 'application/json'
      }
    };

    const req = http.request(options, (res) => {
      let data = '';
      
      res.on('data', (chunk) => {
        data += chunk;
      });
      
      res.on('end', () => {
        try {
          const jsonData = JSON.parse(data);
          resolve({ status: res.statusCode, data: jsonData });
        } catch (error) {
          resolve({ status: res.statusCode, data: data });
        }
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.setTimeout(TIMEOUT, () => {
      req.destroy();
      reject(new Error('Request timeout'));
    });

    if (body) {
      req.write(JSON.stringify(body));
    }

    req.end();
  });
}

async function testEndpoint(name, testFn) {
  try {
    console.log(`🧪 Testing ${name}...`);
    const result = await testFn();
    console.log(`✅ ${name}: PASS`);
    return { name, status: 'PASS', result };
  } catch (error) {
    console.log(`❌ ${name}: FAIL - ${error.message}`);
    return { name, status: 'FAIL', error: error.message };
  }
}

async function runTests() {
  console.log('🚀 SPORE UI Mock Server Integration Tests');
  console.log('==========================================');
  console.log('');
  
  const results = [];
  
  // Test 1: Health Check
  results.push(await testEndpoint('Health Check', async () => {
    const response = await makeRequest('/api/health');
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!response.data.status) {
      throw new Error('Missing status field');
    }
    if (!response.data.mock) {
      throw new Error('Missing mock field');
    }
    return response.data;
  }));
  
  // Test 2: Discovery Nodes
  results.push(await testEndpoint('Discovery Nodes', async () => {
    const response = await makeRequest('/api/discovery/nodes');
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!response.data.primaryNode) {
      throw new Error('Missing primaryNode field');
    }
    if (!Array.isArray(response.data.nodes)) {
      throw new Error('Nodes should be an array');
    }
    return response.data;
  }));
  
  // Test 3: Task Status
  results.push(await testEndpoint('Task Status', async () => {
    const response = await makeRequest('/api/tasks/status');
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!response.data.summary) {
      throw new Error('Missing summary field');
    }
    if (!Array.isArray(response.data.tasks)) {
      throw new Error('Tasks should be an array');
    }
    return response.data;
  }));
  
  // Test 4: Task Control
  results.push(await testEndpoint('Task Control', async () => {
    const response = await makeRequest('/api/tasks/control', 'POST', {
      task: 'heartbeat',
      action: 'status'
    });
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!response.data.success) {
      throw new Error('Task control should succeed');
    }
    return response.data;
  }));
  
  // Test 5: System Status
  results.push(await testEndpoint('System Status', async () => {
    const response = await makeRequest('/api/node/status');
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (typeof response.data.freeHeap !== 'number') {
      throw new Error('freeHeap should be a number');
    }
    if (!response.data.chipId) {
      throw new Error('Missing chipId field');
    }
    return response.data;
  }));
  
  // Test 6: Cluster Members
  results.push(await testEndpoint('Cluster Members', async () => {
    const response = await makeRequest('/api/cluster/members');
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!Array.isArray(response.data.members)) {
      throw new Error('Members should be an array');
    }
    return response.data;
  }));
  
  // Test 7: Random Primary Selection
  results.push(await testEndpoint('Random Primary Selection', async () => {
    const response = await makeRequest('/api/discovery/random-primary', 'POST', {
      timestamp: new Date().toISOString()
    });
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    if (!response.data.success) {
      throw new Error('Random selection should succeed');
    }
    return response.data;
  }));
  
  // Test 8: Proxy Call
  results.push(await testEndpoint('Proxy Call', async () => {
    const response = await makeRequest('/api/proxy-call', 'POST', {
      ip: '192.168.1.100',
      method: 'GET',
      uri: '/api/node/status'
    });
    if (response.status !== 200) {
      throw new Error(`Expected status 200, got ${response.status}`);
    }
    return response.data;
  }));
  
  // Test 9: Error Handling
  results.push(await testEndpoint('Error Handling', async () => {
    const response = await makeRequest('/api/tasks/control', 'POST', {
      task: 'nonexistent',
      action: 'status'
    });
    if (response.status !== 404) {
      throw new Error(`Expected status 404, got ${response.status}`);
    }
    return response.data;
  }));
  
  // Test 10: Invalid Parameters
  results.push(await testEndpoint('Invalid Parameters', async () => {
    const response = await makeRequest('/api/tasks/control', 'POST', {
      // Missing required fields
    });
    if (response.status !== 400) {
      throw new Error(`Expected status 400, got ${response.status}`);
    }
    return response.data;
  }));
  
  // Print Results
  console.log('');
  console.log('📊 Test Results');
  console.log('===============');
  
  const passed = results.filter(r => r.status === 'PASS').length;
  const failed = results.filter(r => r.status === 'FAIL').length;
  const total = results.length;
  
  results.forEach(result => {
    const status = result.status === 'PASS' ? '✅' : '❌';
    console.log(`${status} ${result.name}`);
    if (result.status === 'FAIL') {
      console.log(`   Error: ${result.error}`);
    }
  });
  
  console.log('');
  console.log(`Total: ${total} | Passed: ${passed} | Failed: ${failed}`);
  
  if (failed === 0) {
    console.log('');
    console.log('🎉 All tests passed! Mock server is working correctly.');
  } else {
    console.log('');
    console.log('⚠️  Some tests failed. Check the mock server configuration.');
  }
  
  return failed === 0;
}

// Check if mock server is running
async function checkMockServer() {
  try {
    const response = await makeRequest('/api/health');
    return response.status === 200;
  } catch (error) {
    return false;
  }
}

async function main() {
  console.log('🔍 Checking if mock server is running...');
  
  const isRunning = await checkMockServer();
  if (!isRunning) {
    console.log('❌ Mock server is not running!');
    console.log('');
    console.log('Please start the mock server first:');
    console.log('  npm run mock:healthy');
    console.log('');
    process.exit(1);
  }
  
  console.log('✅ Mock server is running');
  console.log('');
  
  const success = await runTests();
  process.exit(success ? 0 : 1);
}

// Run tests
if (require.main === module) {
  main().catch(error => {
    console.error('❌ Test runner failed:', error.message);
    process.exit(1);
  });
}

module.exports = { runTests, checkMockServer };
