import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as net from 'net';
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';

const TEST_PORT = 30041;
const TEST_TIMEOUT = 30000;

let testServer: ITestServer;

tap.test('setup - start test server', async () => {
  testServer = await startTestServer({
    port: TEST_PORT,
    hostname: 'localhost'
  });
  expect(testServer).toBeDefined();
});

tap.test('Unusual MIME Types - should handle email with various unusual MIME types', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: TEST_TIMEOUT
  });
  
  let receivedData = '';
  let currentStep = 'connecting';
  
  socket.on('data', (data) => {
    receivedData += data.toString();
    console.log('Server response:', data.toString());
    
    if (currentStep === 'connecting' && receivedData.includes('220')) {
      currentStep = 'ehlo';
      receivedData = '';
      socket.write('EHLO testclient\r\n');
    } else if (currentStep === 'ehlo' && receivedData.includes('250 ')) {
      currentStep = 'mail_from';
      receivedData = '';
      socket.write('MAIL FROM:<sender@example.com>\r\n');
    } else if (currentStep === 'mail_from' && receivedData.includes('250')) {
      currentStep = 'rcpt_to';
      receivedData = '';
      socket.write('RCPT TO:<recipient@example.com>\r\n');
    } else if (currentStep === 'rcpt_to' && receivedData.includes('250')) {
      currentStep = 'data';
      receivedData = '';
      socket.write('DATA\r\n');
    } else if (currentStep === 'data' && receivedData.includes('354')) {
      // Create multipart email with unusual MIME types
      const boundary = '----=_Part_1_' + Date.now();
      const unusualMimeTypes = [
        { type: 'text/plain', content: 'This is plain text content.' },
        { type: 'application/x-custom-unusual-type', content: 'Custom proprietary format data' },
        { type: 'model/vrml', content: '#VRML V2.0 utf8\nShape { geometry Box {} }' },
        { type: 'chemical/x-mdl-molfile', content: 'Molecule data\n  -ISIS-  04249412312D\n\n  3  2  0  0  0  0  0  0  0  0999 V2000' },
        { type: 'application/vnd.ms-fontobject', content: 'Font binary data simulation' },
        { type: 'application/x-doom', content: 'IWAD game data simulation' }
      ];
      
      let emailContent = [
        'Subject: Email with Unusual MIME Types',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/mixed; boundary="${boundary}"`,
        '',
        'This is a multipart message with unusual MIME types.',
        ''
      ];
      
      // Add each unusual MIME type as a part
      unusualMimeTypes.forEach((mime, index) => {
        emailContent.push(`--${boundary}`);
        emailContent.push(`Content-Type: ${mime.type}`);
        emailContent.push(`Content-Disposition: attachment; filename="part${index + 1}"`);
        emailContent.push('');
        emailContent.push(mime.content);
        emailContent.push('');
      });
      
      emailContent.push(`--${boundary}--`);
      emailContent.push('.');
      emailContent.push('');
      
      const fullEmail = emailContent.join('\r\n');
      console.log(`Sending email with ${unusualMimeTypes.length} unusual MIME types`);
      
      socket.write(fullEmail);
      currentStep = 'waiting_response';
      receivedData = '';
    } else if (currentStep === 'waiting_response' && (receivedData.includes('250 ') || 
               receivedData.includes('552 ') || 
               receivedData.includes('554 ') || 
               receivedData.includes('500 '))) {
      // Either accepted or gracefully rejected
      const accepted = receivedData.includes('250 ');
      console.log(`Unusual MIME types 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('Unusual MIME Types - should handle email with deeply nested multipart structure', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: TEST_TIMEOUT
  });
  
  let receivedData = '';
  let currentStep = 'connecting';
  
  socket.on('data', (data) => {
    receivedData += data.toString();
    console.log('Server response:', data.toString());
    
    if (currentStep === 'connecting' && receivedData.includes('220')) {
      currentStep = 'ehlo';
      receivedData = '';
      socket.write('EHLO testclient\r\n');
    } else if (currentStep === 'ehlo' && receivedData.includes('250 ')) {
      currentStep = 'mail_from';
      receivedData = '';
      socket.write('MAIL FROM:<sender@example.com>\r\n');
    } else if (currentStep === 'mail_from' && receivedData.includes('250')) {
      currentStep = 'rcpt_to';
      receivedData = '';
      socket.write('RCPT TO:<recipient@example.com>\r\n');
    } else if (currentStep === 'rcpt_to' && receivedData.includes('250')) {
      currentStep = 'data';
      receivedData = '';
      socket.write('DATA\r\n');
    } else if (currentStep === 'data' && receivedData.includes('354')) {
      // Create nested multipart structure
      const boundary1 = '----=_Part_Outer_' + Date.now();
      const boundary2 = '----=_Part_Inner_' + Date.now();
      
      let emailContent = [
        'Subject: Nested Multipart Email',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/mixed; boundary="${boundary1}"`,
        '',
        'This is a nested multipart message.',
        '',
        `--${boundary1}`,
        'Content-Type: text/plain',
        '',
        'First level plain text.',
        '',
        `--${boundary1}`,
        `Content-Type: multipart/alternative; boundary="${boundary2}"`,
        '',
        `--${boundary2}`,
        'Content-Type: text/richtext',
        '',
        '<bold>Rich text content</bold>',
        '',
        `--${boundary2}`,
        'Content-Type: application/rtf',
        '',
        '{\\rtf1 RTF content}',
        '',
        `--${boundary2}--`,
        '',
        `--${boundary1}`,
        'Content-Type: audio/x-aiff',
        'Content-Disposition: attachment; filename="sound.aiff"',
        '',
        'AIFF audio data simulation',
        '',
        `--${boundary1}--`,
        '.',
        ''
      ].join('\r\n');
      
      socket.write(emailContent);
      currentStep = 'waiting_response';
      receivedData = '';
    } else if (currentStep === 'waiting_response' && (receivedData.includes('250 ') || 
               receivedData.includes('552 ') || 
               receivedData.includes('554 ') || 
               receivedData.includes('500 '))) {
      const accepted = receivedData.includes('250 ');
      console.log(`Nested multipart 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('Unusual MIME Types - should handle email with non-standard charset encodings', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: TEST_TIMEOUT
  });
  
  let receivedData = '';
  let currentStep = 'connecting';
  
  socket.on('data', (data) => {
    receivedData += data.toString();
    console.log('Server response:', data.toString());
    
    if (currentStep === 'connecting' && receivedData.includes('220')) {
      currentStep = 'ehlo';
      receivedData = '';
      socket.write('EHLO testclient\r\n');
    } else if (currentStep === 'ehlo' && receivedData.includes('250 ')) {
      currentStep = 'mail_from';
      receivedData = '';
      socket.write('MAIL FROM:<sender@example.com>\r\n');
    } else if (currentStep === 'mail_from' && receivedData.includes('250')) {
      currentStep = 'rcpt_to';
      receivedData = '';
      socket.write('RCPT TO:<recipient@example.com>\r\n');
    } else if (currentStep === 'rcpt_to' && receivedData.includes('250')) {
      currentStep = 'data';
      receivedData = '';
      socket.write('DATA\r\n');
    } else if (currentStep === 'data' && receivedData.includes('354')) {
      // Create email with various charset encodings
      const boundary = '----=_Part_Charset_' + Date.now();
      
      let emailContent = [
        'Subject: Email with Various Charset Encodings',
        'From: sender@example.com',
        'To: recipient@example.com',
        'MIME-Version: 1.0',
        `Content-Type: multipart/mixed; boundary="${boundary}"`,
        '',
        'This email contains various charset encodings.',
        '',
        `--${boundary}`,
        'Content-Type: text/plain; charset="iso-2022-jp"',
        '',
        'Japanese text simulation',
        '',
        `--${boundary}`,
        'Content-Type: text/plain; charset="windows-1251"',
        '',
        'Cyrillic text simulation',
        '',
        `--${boundary}`,
        'Content-Type: text/plain; charset="koi8-r"',
        '',
        'Russian KOI8-R text',
        '',
        `--${boundary}`,
        'Content-Type: text/plain; charset="gb2312"',
        '',
        'Chinese GB2312 text',
        '',
        `--${boundary}--`,
        '.',
        ''
      ].join('\r\n');
      
      socket.write(emailContent);
      currentStep = 'waiting_response';
      receivedData = '';
    } else if (currentStep === 'waiting_response' && (receivedData.includes('250 ') || 
               receivedData.includes('552 ') || 
               receivedData.includes('554 ') || 
               receivedData.includes('500 '))) {
      const accepted = receivedData.includes('250 ');
      console.log(`Various charset 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);
  expect(true).toEqual(true);
});

export default tap.start();