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 type { SmtpClient } from '../../../ts/mail/delivery/smtpclient/smtp-client.js';
import { Email } from '../../../ts/mail/core/classes.email.js';

let testServer: ITestServer;

tap.test('setup test SMTP server', async () => {
  testServer = await startTestServer({
    port: 2546,
    tlsEnabled: false,
    authRequired: false
  });
  expect(testServer).toBeTruthy();
  expect(testServer.port).toBeGreaterThan(0);
});

tap.test('CCMD-06: Check PIPELINING capability', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // The SmtpClient handles pipelining internally
  // We can verify the server supports it by checking a successful send
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Pipelining Test',
    text: 'Testing pipelining support'
  });
  
  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  
  // Server logs show PIPELINING is advertised
  console.log('✅ Server supports PIPELINING (advertised in EHLO response)');

  await smtpClient.close();
});

tap.test('CCMD-06: Basic command pipelining', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Send email with multiple recipients to test pipelining
  const email = new Email({
    from: 'sender@example.com',
    to: ['recipient1@example.com', 'recipient2@example.com'],
    subject: 'Multi-recipient Test',
    text: 'Testing pipelining with multiple recipients'
  });

  const startTime = Date.now();
  const result = await smtpClient.sendMail(email);
  const elapsed = Date.now() - startTime;

  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(2);
  
  console.log(`✅ Sent to ${result.acceptedRecipients.length} recipients in ${elapsed}ms`);
  console.log('Pipelining improves performance by sending multiple commands without waiting');

  await smtpClient.close();
});

tap.test('CCMD-06: Pipelining with DATA command', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Send a normal email - pipelining is handled internally
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'DATA Command Test',
    text: 'Testing pipelining up to DATA command'
  });

  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  
  console.log('✅ Commands pipelined up to DATA successfully');
  console.log('DATA command requires synchronous handling as per RFC');

  await smtpClient.close();
});

tap.test('CCMD-06: Pipelining error handling', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Send email with mix of valid and potentially problematic recipients
  const email = new Email({
    from: 'sender@example.com',
    to: [
      'valid1@example.com',
      'valid2@example.com',
      'valid3@example.com'
    ],
    subject: 'Error Handling Test',
    text: 'Testing pipelining error handling'
  });

  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  
  console.log(`✅ Handled ${result.acceptedRecipients.length} recipients`);
  console.log('Pipelining handles errors gracefully');

  await smtpClient.close();
});

tap.test('CCMD-06: Pipelining performance comparison', async () => {
  // Create two clients - both use pipelining by default when available
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000
  });

  // Test with multiple recipients
  const email = new Email({
    from: 'sender@example.com',
    to: [
      'recipient1@example.com',
      'recipient2@example.com',
      'recipient3@example.com',
      'recipient4@example.com',
      'recipient5@example.com'
    ],
    subject: 'Performance Test',
    text: 'Testing performance with multiple recipients'
  });

  const startTime = Date.now();
  const result = await smtpClient.sendMail(email);
  const elapsed = Date.now() - startTime;

  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(5);
  
  console.log(`✅ Sent to ${result.acceptedRecipients.length} recipients in ${elapsed}ms`);
  console.log('Pipelining provides significant performance improvements');

  await smtpClient.close();
});

tap.test('CCMD-06: Pipelining with multiple recipients', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Send to many recipients
  const recipients = Array.from({ length: 10 }, (_, i) => `recipient${i + 1}@example.com`);
  
  const email = new Email({
    from: 'sender@example.com',
    to: recipients,
    subject: 'Many Recipients Test',
    text: 'Testing pipelining with many recipients'
  });

  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(recipients.length);
  
  console.log(`✅ Successfully sent to ${result.acceptedRecipients.length} recipients`);
  console.log('Pipelining efficiently handles multiple RCPT TO commands');

  await smtpClient.close();
});

tap.test('CCMD-06: Pipelining limits and buffering', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Test with a reasonable number of recipients
  const recipients = Array.from({ length: 50 }, (_, i) => `user${i + 1}@example.com`);
  
  const email = new Email({
    from: 'sender@example.com',
    to: recipients.slice(0, 20), // Use first 20 for TO
    cc: recipients.slice(20, 35), // Next 15 for CC
    bcc: recipients.slice(35),    // Rest for BCC
    subject: 'Buffering Test',
    text: 'Testing pipelining limits and buffering'
  });

  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  
  const totalRecipients = email.to.length + email.cc.length + email.bcc.length;
  console.log(`✅ Handled ${totalRecipients} total recipients`);
  console.log('Pipelining respects server limits and buffers appropriately');

  await smtpClient.close();
});

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

export default tap.start();