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';
import * as net from 'net';

let testServer: ITestServer;

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

tap.test('CREL-02: Handle network interruption during verification', async () => {
  // Create a server that drops connections mid-session
  const interruptServer = net.createServer((socket) => {
    socket.write('220 Interrupt Test Server\r\n');
    
    socket.on('data', (data) => {
      const command = data.toString().trim();
      console.log(`Server received: ${command}`);
      
      if (command.startsWith('EHLO')) {
        // Start sending multi-line response then drop
        socket.write('250-test.server\r\n');
        socket.write('250-PIPELINING\r\n');
        
        // Simulate network interruption
        setTimeout(() => {
          console.log('Simulating network interruption...');
          socket.destroy();
        }, 100);
      }
    });
  });

  await new Promise<void>((resolve) => {
    interruptServer.listen(2602, () => resolve());
  });

  const smtpClient = createSmtpClient({
    host: '127.0.0.1',
    port: 2602,
    secure: false,
    connectionTimeout: 2000,
    debug: true
  });

  // Should handle the interruption gracefully
  const result = await smtpClient.verify();
  expect(result).toBeFalse();
  console.log('✅ Handled network interruption during verification');

  await new Promise<void>((resolve) => {
    interruptServer.close(() => resolve());
  });
});

tap.test('CREL-02: Recovery after brief network glitch', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Send email successfully
  const email1 = new Email({
    from: 'sender@example.com',
    to: ['recipient@example.com'],
    subject: 'Before Glitch',
    text: 'First email before network glitch'
  });

  const result1 = await smtpClient.sendMail(email1);
  expect(result1.success).toBeTrue();
  console.log('First email sent successfully');

  // Close to simulate brief network issue
  await smtpClient.close();
  console.log('Simulating brief network glitch...');
  
  // Wait a moment
  await new Promise(resolve => setTimeout(resolve, 500));

  // Try to send another email - should reconnect automatically
  const email2 = new Email({
    from: 'sender@example.com',
    to: ['recipient@example.com'],
    subject: 'After Glitch',
    text: 'Second email after network recovery'
  });

  const result2 = await smtpClient.sendMail(email2);
  expect(result2.success).toBeTrue();
  console.log('✅ Recovered from network glitch successfully');

  await smtpClient.close();
});

tap.test('CREL-02: Handle server becoming unresponsive', async () => {
  // Create a server that stops responding
  const unresponsiveServer = net.createServer((socket) => {
    socket.write('220 Unresponsive Server\r\n');
    let commandCount = 0;
    
    socket.on('data', (data) => {
      const command = data.toString().trim();
      commandCount++;
      console.log(`Command ${commandCount}: ${command}`);
      
      // Stop responding after first command
      if (commandCount === 1 && command.startsWith('EHLO')) {
        console.log('Server becoming unresponsive...');
        // Don't send any response - simulate hung server
      }
    });
    
    // Don't close the socket, just stop responding
  });

  await new Promise<void>((resolve) => {
    unresponsiveServer.listen(2604, () => resolve());
  });

  const smtpClient = createSmtpClient({
    host: '127.0.0.1',
    port: 2604,
    secure: false,
    connectionTimeout: 2000, // Short timeout to detect unresponsiveness
    debug: true
  });

  // Should timeout when server doesn't respond
  const result = await smtpClient.verify();
  expect(result).toBeFalse();
  console.log('✅ Detected unresponsive server');

  await new Promise<void>((resolve) => {
    unresponsiveServer.close(() => resolve());
  });
});

tap.test('CREL-02: Handle large email successfully', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 10000,
    socketTimeout: 10000,
    debug: true
  });

  // Create a large email
  const largeText = 'x'.repeat(10000); // 10KB of text
  const email = new Email({
    from: 'sender@example.com',
    to: ['recipient@example.com'],
    subject: 'Large Email Test',
    text: largeText
  });

  // Should complete successfully despite size
  const result = await smtpClient.sendMail(email);
  expect(result.success).toBeTrue();
  console.log('✅ Large email sent successfully');

  await smtpClient.close();
});

tap.test('CREL-02: Rapid reconnection after interruption', async () => {
  const smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Rapid cycle of verify, close, verify
  for (let i = 0; i < 3; i++) {
    const result = await smtpClient.verify();
    expect(result).toBeTrue();
    
    await smtpClient.close();
    console.log(`Rapid cycle ${i + 1} completed`);
    
    // Very short delay
    await new Promise(resolve => setTimeout(resolve, 50));
  }

  console.log('✅ Rapid reconnection handled successfully');
});

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

export default tap.start();