import { tap, expect } from '@git.zone/tstest/tapbundle';
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
import * as plugins from '../../../ts/plugins.js';

const TEST_PORT = 2525;
let testServer: ITestServer;

tap.test('setup - start SMTP server with short timeout', async () => {
  testServer = await startTestServer({ 
    port: TEST_PORT,
    timeout: 5000  // 5 second timeout for this test
  });
  
  await new Promise(resolve => setTimeout(resolve, 1000));
});

tap.test('CM-03: Connection Timeout - idle connections are closed after timeout', async (tools) => {
  const startTime = Date.now();
  
  // Create connection
  const socket = await new Promise<plugins.net.Socket>((resolve, reject) => {
    const client = plugins.net.createConnection({
      host: testServer.hostname,
      port: testServer.port
    });
    
    client.on('connect', () => resolve(client));
    client.on('error', reject);
    
    setTimeout(() => reject(new Error('Connection timeout')), 3000);
  });
  
  // Wait for greeting
  await new Promise<void>((resolve) => {
    socket.once('data', (data) => {
      const response = data.toString();
      expect(response).toInclude('220');
      resolve();
    });
  });
  
  console.log('✅ Connected and received greeting');
  
  // Now stay idle and wait for server to timeout the connection
  const disconnectPromise = new Promise<number>((resolve) => {
    socket.on('close', () => {
      const duration = Date.now() - startTime;
      resolve(duration);
    });
    
    socket.on('end', () => {
      console.log('📡 Server initiated connection close');
    });
    
    socket.on('error', (err) => {
      console.log('⚠️ Socket error:', err.message);
    });
  });
  
  // Wait for timeout (should be around 5 seconds)
  const duration = await disconnectPromise;
  
  console.log(`⏱️ Connection closed after ${duration}ms`);
  
  // Verify timeout happened within expected range (4-6 seconds)
  expect(duration).toBeGreaterThan(4000);
  expect(duration).toBeLessThan(7000);
  
  console.log('✅ Connection timeout test passed');
});

tap.test('CM-03: Active connection should not timeout', async () => {
  // Create new connection
  const socket = plugins.net.createConnection({
    host: testServer.hostname,
    port: testServer.port
  });
  
  await new Promise<void>((resolve) => {
    socket.on('connect', resolve);
  });
  
  // Wait for greeting
  await new Promise<void>((resolve) => {
    socket.once('data', resolve);
  });
  
  // Keep connection active with NOOP commands
  let isConnected = true;
  socket.on('close', () => {
    isConnected = false;
  });
  
  // Send NOOP every 2 seconds for 8 seconds
  for (let i = 0; i < 4; i++) {
    if (!isConnected) break;
    
    socket.write('NOOP\r\n');
    
    // Wait for response
    await new Promise<void>((resolve) => {
      socket.once('data', (data) => {
        const response = data.toString();
        expect(response).toInclude('250');
        resolve();
      });
    });
    
    console.log(`✅ NOOP ${i + 1}/4 successful`);
    
    // Wait 2 seconds before next NOOP
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  // Connection should still be active
  expect(isConnected).toEqual(true);
  
  // Close connection gracefully
  socket.write('QUIT\r\n');
  await new Promise<void>((resolve) => {
    socket.once('data', () => {
      socket.end();
      resolve();
    });
  });
  
  console.log('✅ Active connection did not timeout');
});

tap.test('cleanup - stop SMTP server', async () => {
  await stopTestServer(testServer);
});

export default tap.start();