import { tap, expect } from '@git.zone/tstest/tapbundle';
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js';
import { Email } from '../../../ts/mail/core/classes.email.js';

let testServer: ITestServer;

tap.test('setup test SMTP server', async () => {
  testServer = await startTestServer({
    port: 2537,
    tlsEnabled: false,
    authRequired: false,
    socketTimeout: 30000 // 30 second timeout for keep-alive tests
  });
  expect(testServer).toBeTruthy();
  expect(testServer.port).toEqual(2537);
});

tap.test('CCM-11: Basic keep-alive functionality', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    keepAlive: true,
    keepAliveInterval: 5000, // 5 seconds
    connectionTimeout: 10000,
    debug: true
  });

  // Verify connection works
  const verified = await smtpClient.verify();
  expect(verified).toBeTrue();

  // Send an email to establish connection
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Keep-alive test',
    text: 'Testing connection keep-alive'
  });

  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();

  // Wait to simulate idle time
  await new Promise(resolve => setTimeout(resolve, 3000));

  // Send another email to verify connection is still working
  const result2 = await smtpClient.sendMail(email);
  expect(result2.success).toBeTrue();
  
  console.log('✅ Keep-alive functionality verified');

  await smtpClient.close();
});

tap.test('CCM-11: Connection reuse with keep-alive', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    keepAlive: true,
    keepAliveInterval: 3000,
    connectionTimeout: 10000,
    poolSize: 1, // Use single connection to test keep-alive
    debug: true
  });

  // Send multiple emails with delays to test keep-alive
  const emails = [];
  for (let i = 0; i < 3; i++) {
    const email = new Email({
      from: 'sender@example.com',
      to: 'recipient@example.com',
      subject: `Keep-alive test ${i + 1}`,
      text: `Testing connection keep-alive - email ${i + 1}`
    });
    
    const result = await smtpClient.sendMail(email);
    expect(result.success).toBeTrue();
    emails.push(result);
    
    // Wait between emails (less than keep-alive interval)
    if (i < 2) {
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }

  // All emails should have been sent successfully
  expect(emails.length).toEqual(3);
  expect(emails.every(r => r.success)).toBeTrue();
  
  console.log('✅ Connection reused successfully with keep-alive');

  await smtpClient.close();
});

tap.test('CCM-11: Connection without keep-alive', async () => {
  // Create a client without keep-alive
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    keepAlive: false, // Disabled
    connectionTimeout: 5000,
    socketTimeout: 5000, // 5 second socket timeout
    poolSize: 1,
    debug: true
  });

  // Send first email
  const email1 = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'No keep-alive test 1',
    text: 'Testing without keep-alive'
  });
  
  const result1 = await smtpClient.sendMail(email1);
  expect(result1.success).toBeTrue();
  
  // Wait longer than socket timeout
  await new Promise(resolve => setTimeout(resolve, 7000));
  
  // Send second email - connection might need to be re-established
  const email2 = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'No keep-alive test 2',
    text: 'Testing without keep-alive after timeout'
  });
  
  const result2 = await smtpClient.sendMail(email2);
  expect(result2.success).toBeTrue();
  
  console.log('✅ Client handles reconnection without keep-alive');

  await smtpClient.close();
});

tap.test('CCM-11: Keep-alive with long operations', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    keepAlive: true,
    keepAliveInterval: 2000,
    connectionTimeout: 10000,
    poolSize: 2, // Use small pool
    debug: true
  });

  // Send multiple emails with varying delays
  const operations = [];
  
  for (let i = 0; i < 5; i++) {
    operations.push((async () => {
      // Simulate random processing delay
      await new Promise(resolve => setTimeout(resolve, Math.random() * 3000));
      
      const email = new Email({
        from: 'sender@example.com',
        to: 'recipient@example.com',
        subject: `Long operation test ${i + 1}`,
        text: `Testing keep-alive during long operations - email ${i + 1}`
      });
      
      const result = await smtpClient.sendMail(email);
      return { index: i, result };
    })());
  }
  
  const results = await Promise.all(operations);
  
  // All operations should succeed
  const successCount = results.filter(r => r.result.success).length;
  expect(successCount).toEqual(5);
  
  console.log('✅ Keep-alive maintained during long operations');

  await smtpClient.close();
});

tap.test('CCM-11: Keep-alive interval effect on connection pool', async () => {
  const intervals = [1000, 3000, 5000]; // Different intervals to test
  
  for (const interval of intervals) {
    console.log(`\nTesting keep-alive with ${interval}ms interval`);
    
    const smtpClient = createSmtpClient({
      host: testServer.hostname,
      port: testServer.port,
      secure: false,
      keepAlive: true,
      keepAliveInterval: interval,
      connectionTimeout: 10000,
      poolSize: 2,
      debug: false // Less verbose for this test
    });

    const startTime = Date.now();
    
    // Send multiple emails over time period longer than interval
    const emails = [];
    for (let i = 0; i < 3; i++) {
      const email = new Email({
        from: 'sender@example.com',
        to: 'recipient@example.com',
        subject: `Interval test ${i + 1}`,
        text: `Testing with ${interval}ms keep-alive interval`
      });
      
      const result = await smtpClient.sendMail(email);
      expect(result.success).toBeTrue();
      emails.push(result);
      
      // Wait approximately one interval
      if (i < 2) {
        await new Promise(resolve => setTimeout(resolve, interval));
      }
    }
    
    const totalTime = Date.now() - startTime;
    console.log(`Sent ${emails.length} emails in ${totalTime}ms with ${interval}ms keep-alive`);
    
    // Check pool status
    const poolStatus = smtpClient.getPoolStatus();
    console.log(`Pool status: ${JSON.stringify(poolStatus)}`);

    await smtpClient.close();
  }
});

tap.test('CCM-11: Event monitoring during keep-alive', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    keepAlive: true,
    keepAliveInterval: 2000,
    connectionTimeout: 10000,
    poolSize: 1,
    debug: true
  });

  let connectionEvents = 0;
  let disconnectEvents = 0;
  let errorEvents = 0;

  // Monitor events
  smtpClient.on('connection', () => {
    connectionEvents++;
    console.log('📡 Connection event');
  });

  smtpClient.on('disconnect', () => {
    disconnectEvents++;
    console.log('🔌 Disconnect event');
  });

  smtpClient.on('error', (error) => {
    errorEvents++;
    console.log('❌ Error event:', error.message);
  });

  // Send emails with delays
  for (let i = 0; i < 3; i++) {
    const email = new Email({
      from: 'sender@example.com',
      to: 'recipient@example.com',
      subject: `Event test ${i + 1}`,
      text: 'Testing events during keep-alive'
    });
    
    const result = await smtpClient.sendMail(email);
    expect(result.success).toBeTrue();
    
    if (i < 2) {
      await new Promise(resolve => setTimeout(resolve, 1500));
    }
  }

  // Should have at least one connection event
  expect(connectionEvents).toBeGreaterThan(0);
  console.log(`✅ Captured ${connectionEvents} connection events`);

  await smtpClient.close();
  
  // Wait a bit for close event
  await new Promise(resolve => setTimeout(resolve, 100));
});

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

export default tap.start();