import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as plugins from '../../../ts/plugins.js';
import * as net from 'net';
import { startTestServer, stopTestServer } from '../../helpers/server.loader.ts'
import type { ITestServer } from '../../helpers/server.loader.js';
let testServer: ITestServer;
const TEST_PORT = 2525;

tap.test('setup - start test server', async () => {
  testServer = await startTestServer({ port: TEST_PORT });
  await new Promise(resolve => setTimeout(resolve, 1000));
});

tap.test('Nested MIME Structures - should handle deeply nested multipart structure', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  let dataBuffer = '';
  let state = 'initial';
  
  socket.on('data', (data) => {
    dataBuffer += data.toString();
    console.log('Server response:', data.toString());
    
    if (dataBuffer.includes('220 ') && state === 'initial') {
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      state = 'ehlo_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'ehlo_sent') {
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      state = 'mail_from_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'mail_from_sent') {
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      state = 'rcpt_to_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'rcpt_to_sent') {
      // Send DATA
      socket.write('DATA\r\n');
      state = 'data_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('354 ') && state === 'data_sent') {
      // Create deeply nested MIME structure (4 levels)
      const outerBoundary = '----=_Outer_Boundary_' + Date.now();
      const middleBoundary = '----=_Middle_Boundary_' + Date.now();
      const innerBoundary = '----=_Inner_Boundary_' + Date.now();
      const deepBoundary = '----=_Deep_Boundary_' + Date.now();
      
      let emailContent = [
        'Subject: Deeply Nested MIME Structure Test',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/mixed; boundary="${outerBoundary}"`,
        '',
        'This is a multipart message with deeply nested structure.',
        '',
        // Level 1: Outer boundary
        `--${outerBoundary}`,
        'Content-Type: text/plain',
        '',
        'This is the first part at the outer level.',
        '',
        `--${outerBoundary}`,
        `Content-Type: multipart/alternative; boundary="${middleBoundary}"`,
        '',
        // Level 2: Middle boundary
        `--${middleBoundary}`,
        'Content-Type: text/plain',
        '',
        'Alternative plain text version.',
        '',
        `--${middleBoundary}`,
        `Content-Type: multipart/related; boundary="${innerBoundary}"`,
        '',
        // Level 3: Inner boundary
        `--${innerBoundary}`,
        'Content-Type: text/html',
        '',
        '<html><body><h1>HTML with related content</h1><img src="cid:image1"></body></html>',
        '',
        `--${innerBoundary}`,
        'Content-Type: image/png',
        'Content-ID: <image1>',
        'Content-Transfer-Encoding: base64',
        '',
        'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
        '',
        `--${innerBoundary}`,
        `Content-Type: multipart/mixed; boundary="${deepBoundary}"`,
        '',
        // Level 4: Deep boundary
        `--${deepBoundary}`,
        'Content-Type: application/octet-stream',
        'Content-Disposition: attachment; filename="data.bin"',
        '',
        'Binary data simulation',
        '',
        `--${deepBoundary}`,
        'Content-Type: message/rfc822',
        '',
        'Subject: Embedded Message',
        'From: embedded@example.com',
        'To: recipient@example.com',
        '',
        'This is an embedded email message.',
        '',
        `--${deepBoundary}--`,
        '',
        `--${innerBoundary}--`,
        '',
        `--${middleBoundary}--`,
        '',
        `--${outerBoundary}`,
        'Content-Type: application/pdf',
        'Content-Disposition: attachment; filename="document.pdf"',
        '',
        'PDF document data simulation',
        '',
        `--${outerBoundary}--`,
        '.',
        ''
      ].join('\r\n');
      
      console.log('Sending email with 4-level nested MIME structure');
      socket.write(emailContent);
      state = 'email_sent';
      dataBuffer = '';
    } else if ((dataBuffer.includes('250 OK') && state === 'email_sent') || 
               dataBuffer.includes('552 ') || 
               dataBuffer.includes('554 ') || 
               dataBuffer.includes('500 ')) {
      // Either accepted or gracefully rejected
      const accepted = dataBuffer.includes('250 ');
      console.log(`Nested MIME structure test ${accepted ? 'accepted' : 'rejected'}`);
      
      socket.write('QUIT\r\n');
      socket.end();
      done.resolve();
    }
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('timeout', () => {
    console.error('Socket timeout');
    socket.destroy();
    done.reject(new Error('Socket timeout'));
  });
  
  await done.promise;
});

tap.test('Nested MIME Structures - should handle circular references in multipart structure', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  let dataBuffer = '';
  let state = 'initial';
  
  socket.on('data', (data) => {
    dataBuffer += data.toString();
    console.log('Server response:', data.toString());
    
    if (dataBuffer.includes('220 ') && state === 'initial') {
      socket.write('EHLO testclient\r\n');
      state = 'ehlo_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'ehlo_sent') {
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      state = 'mail_from_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'mail_from_sent') {
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      state = 'rcpt_to_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'rcpt_to_sent') {
      socket.write('DATA\r\n');
      state = 'data_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('354 ') && state === 'data_sent') {
      // Create structure with references between parts
      const boundary1 = '----=_Boundary1_' + Date.now();
      const boundary2 = '----=_Boundary2_' + Date.now();
      
      let emailContent = [
        'Subject: Multipart with Cross-References',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/related; boundary="${boundary1}"`,
        '',
        `--${boundary1}`,
        `Content-Type: multipart/alternative; boundary="${boundary2}"`,
        'Content-ID: <part1>',
        '',
        `--${boundary2}`,
        'Content-Type: text/html',
        '',
        '<html><body>See related part: <a href="cid:part2">Link</a></body></html>',
        '',
        `--${boundary2}`,
        'Content-Type: text/plain',
        '',
        'Plain text with reference to part2',
        '',
        `--${boundary2}--`,
        '',
        `--${boundary1}`,
        'Content-Type: application/xml',
        'Content-ID: <part2>',
        '',
        '<?xml version="1.0"?><root><reference href="cid:part1"/></root>',
        '',
        `--${boundary1}--`,
        '.',
        ''
      ].join('\r\n');
      
      socket.write(emailContent);
      state = 'email_sent';
      dataBuffer = '';
    } else if ((dataBuffer.includes('250 OK') && state === 'email_sent') || 
               dataBuffer.includes('552 ') || 
               dataBuffer.includes('554 ') || 
               dataBuffer.includes('500 ')) {
      const accepted = dataBuffer.includes('250 ');
      console.log(`Cross-reference test ${accepted ? 'accepted' : 'rejected'}`);
      
      socket.write('QUIT\r\n');
      socket.end();
      done.resolve();
    }
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('timeout', () => {
    console.error('Socket timeout');
    socket.destroy();
    done.reject(new Error('Socket timeout'));
  });
  
  await done.promise;
});

tap.test('Nested MIME Structures - should handle mixed nesting with various encodings', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  let dataBuffer = '';
  let state = 'initial';
  
  socket.on('data', (data) => {
    dataBuffer += data.toString();
    console.log('Server response:', data.toString());
    
    if (dataBuffer.includes('220 ') && state === 'initial') {
      socket.write('EHLO testclient\r\n');
      state = 'ehlo_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'ehlo_sent') {
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      state = 'mail_from_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'mail_from_sent') {
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      state = 'rcpt_to_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('250 ') && state === 'rcpt_to_sent') {
      socket.write('DATA\r\n');
      state = 'data_sent';
      dataBuffer = '';
    } else if (dataBuffer.includes('354 ') && state === 'data_sent') {
      // Create structure with various encodings
      const boundary1 = '----=_Encoding_Outer_' + Date.now();
      const boundary2 = '----=_Encoding_Inner_' + Date.now();
      
      let emailContent = [
        'Subject: Mixed Encodings in Nested Structure',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/mixed; boundary="${boundary1}"`,
        '',
        `--${boundary1}`,
        'Content-Type: text/plain; charset="utf-8"',
        'Content-Transfer-Encoding: quoted-printable',
        '',
        'This is quoted-printable encoded: =C3=A9=C3=A8=C3=AA',
        '',
        `--${boundary1}`,
        `Content-Type: multipart/alternative; boundary="${boundary2}"`,
        '',
        `--${boundary2}`,
        'Content-Type: text/plain; charset="iso-8859-1"',
        'Content-Transfer-Encoding: 8bit',
        '',
        'Text with 8-bit characters: ñáéíóú',
        '',
        `--${boundary2}`,
        'Content-Type: text/html; charset="utf-16"',
        'Content-Transfer-Encoding: base64',
        '',
        '//48AGgAdABtAGwAPgA8AGIAbwBkAHkAPgBVAFQARgAtADEANgAgAHQAZQB4AHQAPAAvAGIAbwBkAHkAPgA8AC8AaAB0AG0AbAA+',
        '',
        `--${boundary2}--`,
        '',
        `--${boundary1}`,
        'Content-Type: application/octet-stream',
        'Content-Transfer-Encoding: base64',
        'Content-Disposition: attachment; filename="binary.dat"',
        '',
        'VGhpcyBpcyBiaW5hcnkgZGF0YQ==',
        '',
        `--${boundary1}--`,
        '.',
        ''
      ].join('\r\n');
      
      socket.write(emailContent);
      state = 'email_sent';
      dataBuffer = '';
    } else if ((dataBuffer.includes('250 OK') && state === 'email_sent') || 
               dataBuffer.includes('552 ') || 
               dataBuffer.includes('554 ') || 
               dataBuffer.includes('500 ')) {
      const accepted = dataBuffer.includes('250 ');
      console.log(`Mixed encodings test ${accepted ? 'accepted' : 'rejected'}`);
      
      socket.write('QUIT\r\n');
      socket.end();
      done.resolve();
    }
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('timeout', () => {
    console.error('Socket timeout');
    socket.destroy();
    done.reject(new Error('Socket timeout'));
  });
  
  await done.promise;
});

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

export default tap.start();