import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as net from 'net';
import * as plugins from '../ts/plugins.js';

// Import SmartProxy and configurations
import { SmartProxy } from '../ts/index.js';

tap.test('simple proxy chain test - identify connection accumulation', async () => {
  console.log('\n=== Simple Proxy Chain Test ===');
  console.log('Setup: Client → SmartProxy1 (8590) → SmartProxy2 (8591) → Backend (down)');
  
  // Create backend server that accepts and immediately closes connections
  const backend = net.createServer((socket) => {
    console.log('Backend: Connection received, closing immediately');
    socket.destroy();
  });
  
  await new Promise<void>((resolve) => {
    backend.listen(9998, () => {
      console.log('✓ Backend server started on port 9998 (closes connections immediately)');
      resolve();
    });
  });
  
  // Create SmartProxy2 (downstream)
  const proxy2 = new SmartProxy({
    ports: [8591],
    enableDetailedLogging: true,
    socketTimeout: 5000,
    routes: [{
      name: 'to-backend',
      match: { ports: 8591 },
      action: {
        type: 'forward',
        target: {
          host: 'localhost',
          port: 9998  // Backend that closes immediately
        }
      }
    }]
  });
  
  // Create SmartProxy1 (upstream)
  const proxy1 = new SmartProxy({
    ports: [8590],
    enableDetailedLogging: true,
    socketTimeout: 5000,
    routes: [{
      name: 'to-proxy2',
      match: { ports: 8590 },
      action: {
        type: 'forward',
        target: {
          host: 'localhost',
          port: 8591  // Forward to proxy2
        }
      }
    }]
  });
  
  await proxy2.start();
  console.log('✓ SmartProxy2 started on port 8591');
  
  await proxy1.start();
  console.log('✓ SmartProxy1 started on port 8590');
  
  // Helper to get connection counts
  const getConnectionCounts = () => {
    const conn1 = (proxy1 as any).connectionManager;
    const conn2 = (proxy2 as any).connectionManager;
    return {
      proxy1: conn1 ? conn1.getConnectionCount() : 0,
      proxy2: conn2 ? conn2.getConnectionCount() : 0
    };
  };
  
  console.log('\n--- Making 5 sequential connections ---');
  
  for (let i = 0; i < 5; i++) {
    console.log(`\n=== Connection ${i + 1} ===`);
    
    const counts = getConnectionCounts();
    console.log(`Before: Proxy1=${counts.proxy1}, Proxy2=${counts.proxy2}`);
    
    await new Promise<void>((resolve) => {
      const client = new net.Socket();
      let dataReceived = false;
      
      client.on('data', (data) => {
        console.log(`Client received data: ${data.toString()}`);
        dataReceived = true;
      });
      
      client.on('error', (err) => {
        console.log(`Client error: ${err.code}`);
        resolve();
      });
      
      client.on('close', () => {
        console.log(`Client closed (data received: ${dataReceived})`);
        resolve();
      });
      
      client.connect(8590, 'localhost', () => {
        console.log('Client connected to Proxy1');
        // Send HTTP request
        client.write('GET / HTTP/1.1\r\nHost: test.com\r\n\r\n');
      });
      
      // Timeout
      setTimeout(() => {
        if (!client.destroyed) {
          console.log('Client timeout, destroying');
          client.destroy();
        }
        resolve();
      }, 2000);
    });
    
    // Wait a bit and check counts
    await new Promise(resolve => setTimeout(resolve, 500));
    
    const afterCounts = getConnectionCounts();
    console.log(`After: Proxy1=${afterCounts.proxy1}, Proxy2=${afterCounts.proxy2}`);
    
    if (afterCounts.proxy1 > 0 || afterCounts.proxy2 > 0) {
      console.log('⚠️  WARNING: Connections not cleaned up!');
    }
  }
  
  console.log('\n--- Test with backend completely down ---');
  
  // Stop backend
  backend.close();
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log('✓ Backend stopped');
  
  // Make more connections with backend down
  for (let i = 0; i < 3; i++) {
    console.log(`\n=== Connection ${i + 6} (backend down) ===`);
    
    const counts = getConnectionCounts();
    console.log(`Before: Proxy1=${counts.proxy1}, Proxy2=${counts.proxy2}`);
    
    await new Promise<void>((resolve) => {
      const client = new net.Socket();
      
      client.on('error', () => {
        resolve();
      });
      
      client.on('close', () => {
        resolve();
      });
      
      client.connect(8590, 'localhost', () => {
        client.write('GET / HTTP/1.1\r\nHost: test.com\r\n\r\n');
      });
      
      setTimeout(() => {
        if (!client.destroyed) {
          client.destroy();
        }
        resolve();
      }, 1000);
    });
    
    await new Promise(resolve => setTimeout(resolve, 500));
    
    const afterCounts = getConnectionCounts();
    console.log(`After: Proxy1=${afterCounts.proxy1}, Proxy2=${afterCounts.proxy2}`);
  }
  
  // Final check
  console.log('\n--- Final Check ---');
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  const finalCounts = getConnectionCounts();
  console.log(`Final counts: Proxy1=${finalCounts.proxy1}, Proxy2=${finalCounts.proxy2}`);
  
  await proxy1.stop();
  await proxy2.stop();
  
  // Verify
  if (finalCounts.proxy1 > 0 || finalCounts.proxy2 > 0) {
    console.log('\n❌ FAIL: Connections accumulated!');
  } else {
    console.log('\n✅ PASS: No connection accumulation');
  }
  
  expect(finalCounts.proxy1).toEqual(0);
  expect(finalCounts.proxy2).toEqual(0);
});

tap.start();