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: 2576,
    tlsEnabled: false,
    authRequired: false,
    maxConnections: 20  // Allow more connections for concurrent testing
  });
  expect(testServer).toBeTruthy();
  expect(testServer.port).toEqual(2576);
});

tap.test('CEDGE-07: Multiple simultaneous connections', async () => {
  console.log('Testing multiple simultaneous connections');
  
  const connectionCount = 5;
  const clients = [];
  
  // Create multiple clients
  for (let i = 0; i < connectionCount; i++) {
    const client = createSmtpClient({
      host: testServer.hostname,
      port: testServer.port,
      secure: false,
      connectionTimeout: 5000,
      debug: false, // Reduce noise
      maxConnections: 2
    });
    clients.push(client);
  }

  // Test concurrent verification
  console.log(`  Testing ${connectionCount} concurrent verifications...`);
  const verifyPromises = clients.map(async (client, index) => {
    try {
      const result = await client.verify();
      console.log(`    Client ${index + 1}: ${result ? 'Success' : 'Failed'}`);
      return result;
    } catch (error) {
      console.log(`    Client ${index + 1}: Error - ${error.message}`);
      return false;
    }
  });

  const verifyResults = await Promise.all(verifyPromises);
  const successCount = verifyResults.filter(r => r).length;
  console.log(`  Verify results: ${successCount}/${connectionCount} successful`);
  
  // We expect at least some connections to succeed
  expect(successCount).toBeGreaterThan(0);

  // Clean up clients
  await Promise.all(clients.map(client => client.close().catch(() => {})));
});

tap.test('CEDGE-07: Concurrent email sending', async () => {
  console.log('Testing concurrent email sending');
  
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: false,
    maxConnections: 5
  });

  const emailCount = 10;
  console.log(`  Sending ${emailCount} emails concurrently...`);
  
  const sendPromises = [];
  for (let i = 0; i < emailCount; i++) {
    const email = new Email({
      from: 'sender@example.com',
      to: [`recipient${i}@example.com`],
      subject: `Concurrent test email ${i + 1}`,
      text: `This is concurrent test email number ${i + 1}`
    });

    sendPromises.push(
      smtpClient.sendMail(email).then(
        result => {
          console.log(`    Email ${i + 1}: Success`);
          return { success: true, result };
        },
        error => {
          console.log(`    Email ${i + 1}: Failed - ${error.message}`);
          return { success: false, error };
        }
      )
    );
  }

  const results = await Promise.all(sendPromises);
  const successCount = results.filter(r => r.success).length;
  console.log(`  Send results: ${successCount}/${emailCount} successful`);
  
  // We expect a high success rate
  expect(successCount).toBeGreaterThan(emailCount * 0.7); // At least 70% success

  await smtpClient.close();
});

tap.test('CEDGE-07: Rapid connection cycling', async () => {
  console.log('Testing rapid connection cycling');
  
  const cycleCount = 8;
  console.log(`  Performing ${cycleCount} rapid connect/disconnect cycles...`);
  
  const cyclePromises = [];
  for (let i = 0; i < cycleCount; i++) {
    cyclePromises.push(
      (async () => {
        const client = createSmtpClient({
          host: testServer.hostname,
          port: testServer.port,
          secure: false,
          connectionTimeout: 3000,
          debug: false
        });

        try {
          const verified = await client.verify();
          console.log(`    Cycle ${i + 1}: ${verified ? 'Success' : 'Failed'}`);
          await client.close();
          return verified;
        } catch (error) {
          console.log(`    Cycle ${i + 1}: Error - ${error.message}`);
          await client.close().catch(() => {});
          return false;
        }
      })()
    );
  }

  const cycleResults = await Promise.all(cyclePromises);
  const successCount = cycleResults.filter(r => r).length;
  console.log(`  Cycle results: ${successCount}/${cycleCount} successful`);
  
  // We expect most cycles to succeed
  expect(successCount).toBeGreaterThan(cycleCount * 0.6); // At least 60% success
});

tap.test('CEDGE-07: Connection pool stress test', async () => {
  console.log('Testing connection pool under stress');
  
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: false,
    maxConnections: 3,
    maxMessages: 50
  });

  const stressCount = 15;
  console.log(`  Sending ${stressCount} emails to stress connection pool...`);
  
  const startTime = Date.now();
  const stressPromises = [];
  
  for (let i = 0; i < stressCount; i++) {
    const email = new Email({
      from: 'stress@example.com',
      to: [`stress${i}@example.com`],
      subject: `Stress test ${i + 1}`,
      text: `Connection pool stress test email ${i + 1}`
    });

    stressPromises.push(
      smtpClient.sendMail(email).then(
        result => ({ success: true, index: i }),
        error => ({ success: false, index: i, error: error.message })
      )
    );
  }

  const stressResults = await Promise.all(stressPromises);
  const duration = Date.now() - startTime;
  const successCount = stressResults.filter(r => r.success).length;
  
  console.log(`  Stress results: ${successCount}/${stressCount} successful in ${duration}ms`);
  console.log(`  Average: ${Math.round(duration / stressCount)}ms per email`);
  
  // Under stress, we still expect reasonable success rate
  expect(successCount).toBeGreaterThan(stressCount * 0.5); // At least 50% success under stress
  
  await smtpClient.close();
});

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

export default tap.start();