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

let testServer: ITestServer;
let pooledClient: SmtpClient;

tap.test('setup - start SMTP server for pooling test', async () => {
  testServer = await startTestServer({
    port: 2530,
    tlsEnabled: false,
    authRequired: false,
    maxConnections: 10
  });
  
  expect(testServer.port).toEqual(2530);
});

tap.test('CCM-04: Connection Pooling - should create pooled client', async () => {
  const startTime = Date.now();
  
  try {
    // Create pooled SMTP client
    pooledClient = createPooledSmtpClient({
      host: testServer.hostname,
      port: testServer.port,
      secure: false,
      maxConnections: 5,
      maxMessages: 100,
      connectionTimeout: 5000,
      debug: true
    });
    
    // Verify connection pool is working
    const isConnected = await pooledClient.verify();
    expect(isConnected).toBeTrue();
    
    const poolStatus = pooledClient.getPoolStatus();
    console.log('📊 Initial pool status:', poolStatus);
    expect(poolStatus.total).toBeGreaterThanOrEqual(0);
    
    const duration = Date.now() - startTime;
    console.log(`✅ Connection pool created in ${duration}ms`);
    
  } catch (error) {
    const duration = Date.now() - startTime;
    console.error(`❌ Connection pool creation failed after ${duration}ms:`, error);
    throw error;
  }
});

tap.test('CCM-04: Connection Pooling - should handle concurrent connections', async () => {
  // Send multiple emails concurrently
  const emailPromises = [];
  const concurrentCount = 5;
  
  for (let i = 0; i < concurrentCount; i++) {
    const email = new Email({
      from: 'test@example.com',
      to: `recipient${i}@example.com`,
      subject: `Concurrent Email ${i}`,
      text: `This is concurrent email number ${i}`
    });
    
    emailPromises.push(
      pooledClient.sendMail(email).catch(error => {
        console.error(`❌ Failed to send email ${i}:`, error);
        return { success: false, error: error.message, acceptedRecipients: [] };
      })
    );
  }
  
  // Wait for all emails to be sent
  const results = await Promise.all(emailPromises);
  
  // Check results and count successes
  let successCount = 0;
  results.forEach((result, index) => {
    if (result.success) {
      successCount++;
      expect(result.acceptedRecipients).toContain(`recipient${index}@example.com`);
    } else {
      console.log(`Email ${index} failed:`, result.error);
    }
  });
  
  // At least some emails should succeed with pooling
  expect(successCount).toBeGreaterThan(0);
  console.log(`✅ Sent ${successCount}/${concurrentCount} emails successfully`);
  
  // Check pool status after concurrent sends
  const poolStatus = pooledClient.getPoolStatus();
  console.log('📊 Pool status after concurrent sends:', poolStatus);
  expect(poolStatus.total).toBeGreaterThanOrEqual(1);
  expect(poolStatus.total).toBeLessThanOrEqual(5); // Should not exceed max
});

tap.test('CCM-04: Connection Pooling - should reuse connections', async () => {
  // Get initial pool status
  const initialStatus = pooledClient.getPoolStatus();
  console.log('📊 Initial status:', initialStatus);
  
  // Send emails sequentially to test connection reuse
  const emailCount = 10;
  const connectionCounts = [];
  
  for (let i = 0; i < emailCount; i++) {
    const email = new Email({
      from: 'test@example.com',
      to: 'recipient@example.com',
      subject: `Sequential Email ${i}`,
      text: `Testing connection reuse - email ${i}`
    });
    
    await pooledClient.sendMail(email);
    
    const status = pooledClient.getPoolStatus();
    connectionCounts.push(status.total);
  }
  
  // Check that connections were reused (total shouldn't grow linearly)
  const maxConnections = Math.max(...connectionCounts);
  expect(maxConnections).toBeLessThan(emailCount); // Should reuse connections
  
  console.log(`✅ Sent ${emailCount} emails using max ${maxConnections} connections`);
  console.log('📊 Connection counts:', connectionCounts);
});

tap.test('CCM-04: Connection Pooling - should respect max connections limit', async () => {
  // Create a client with small pool
  const limitedClient = createPooledSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    maxConnections: 2, // Very small pool
    connectionTimeout: 5000
  });
  
  // Send many concurrent emails
  const emailPromises = [];
  for (let i = 0; i < 10; i++) {
    const email = new Email({
      from: 'test@example.com',
      to: `test${i}@example.com`,
      subject: `Pool Limit Test ${i}`,
      text: 'Testing pool limits'
    });
    emailPromises.push(limitedClient.sendMail(email));
  }
  
  // Monitor pool during sending
  const checkInterval = setInterval(() => {
    const status = limitedClient.getPoolStatus();
    console.log('📊 Pool status during load:', status);
    expect(status.total).toBeLessThanOrEqual(2); // Should never exceed max
  }, 100);
  
  await Promise.all(emailPromises);
  clearInterval(checkInterval);
  
  await limitedClient.close();
  console.log('✅ Connection pool respected max connections limit');
});

tap.test('CCM-04: Connection Pooling - should handle connection failures in pool', async () => {
  // Create a new pooled client
  const resilientClient = createPooledSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    maxConnections: 3,
    connectionTimeout: 5000
  });
  
  // Send some emails successfully
  for (let i = 0; i < 3; i++) {
    const email = new Email({
      from: 'test@example.com',
      to: 'recipient@example.com',
      subject: `Pre-failure Email ${i}`,
      text: 'Before simulated failure'
    });
    
    const result = await resilientClient.sendMail(email);
    expect(result.success).toBeTrue();
  }
  
  // Pool should recover and continue working
  const poolStatus = resilientClient.getPoolStatus();
  console.log('📊 Pool status after recovery test:', poolStatus);
  expect(poolStatus.total).toBeGreaterThanOrEqual(1);
  
  await resilientClient.close();
  console.log('✅ Connection pool handled failures gracefully');
});

tap.test('CCM-04: Connection Pooling - should clean up idle connections', async () => {
  // Create client with specific idle settings
  const idleClient = createPooledSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    maxConnections: 5,
    connectionTimeout: 5000
  });
  
  // Send burst of emails
  const promises = [];
  for (let i = 0; i < 5; i++) {
    const email = new Email({
      from: 'test@example.com',
      to: 'recipient@example.com',
      subject: `Idle Test ${i}`,
      text: 'Testing idle cleanup'
    });
    promises.push(idleClient.sendMail(email));
  }
  
  await Promise.all(promises);
  
  const activeStatus = idleClient.getPoolStatus();
  console.log('📊 Pool status after burst:', activeStatus);
  
  // Wait for connections to become idle
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  const idleStatus = idleClient.getPoolStatus();
  console.log('📊 Pool status after idle period:', idleStatus);
  
  await idleClient.close();
  console.log('✅ Idle connection management working');
});

tap.test('cleanup - close pooled client', async () => {
  if (pooledClient && pooledClient.isConnected()) {
    await pooledClient.close();
    
    // Verify pool is cleaned up
    const finalStatus = pooledClient.getPoolStatus();
    console.log('📊 Final pool status:', finalStatus);
  }
});

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

export default tap.start();