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

let testServer: ITestServer;
let smtpClient: SmtpClient;

tap.test('setup - start SMTP server for attachment encoding tests', async () => {
  testServer = await startTestServer({
    port: 2572,
    tlsEnabled: false,
    authRequired: false,
    size: 50 * 1024 * 1024 // 50MB for large attachment tests
  });
  
  expect(testServer.port).toEqual(2572);
});

tap.test('setup - create SMTP client', async () => {
  smtpClient = createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    socketTimeout: 120000, // 2 minutes for large attachments
    debug: true
  });
  
  const isConnected = await smtpClient.verify();
  expect(isConnected).toBeTrue();
});

tap.test('CEP-03: Attachment Encoding - should encode text attachment with base64', async () => {
  const textContent = 'This is a test text file.\nIt contains multiple lines.\nAnd some special characters: © ® ™';
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Text Attachment Base64 Test',
    text: 'Email with text attachment',
    attachments: [{
      filename: 'test.txt',
      content: Buffer.from(textContent),
      contentType: 'text/plain',
      encoding: 'base64'
    }]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Text attachment encoded with base64');
});

tap.test('CEP-03: Attachment Encoding - should encode binary data correctly', async () => {
  // Create binary data with all possible byte values
  const binaryData = Buffer.alloc(256);
  for (let i = 0; i < 256; i++) {
    binaryData[i] = i;
  }
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Binary Attachment Test',
    text: 'Email with binary attachment',
    attachments: [{
      filename: 'binary.dat',
      content: binaryData,
      contentType: 'application/octet-stream'
    }]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Binary data encoded correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle various file types', async () => {
  const attachments = [
    {
      filename: 'image.jpg',
      content: Buffer.from('/9j/4AAQSkZJRgABAQEASABIAAD/2wBD', 'base64'), // Partial JPEG header
      contentType: 'image/jpeg'
    },
    {
      filename: 'document.pdf',
      content: Buffer.from('%PDF-1.4\n%âÃÏÓ\n', 'utf8'),
      contentType: 'application/pdf'
    },
    {
      filename: 'archive.zip',
      content: Buffer.from('PK\x03\x04'), // ZIP magic number
      contentType: 'application/zip'
    },
    {
      filename: 'audio.mp3',
      content: Buffer.from('ID3'), // MP3 ID3 tag
      contentType: 'audio/mpeg'
    }
  ];
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Multiple File Types Test',
    text: 'Testing various attachment types',
    attachments
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Various file types encoded correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle quoted-printable encoding', async () => {
  const textWithSpecialChars = 'This line has special chars: café, naïve, résumé\r\nThis line is very long and might need soft line breaks when encoded with quoted-printable encoding method\r\n=This line starts with equals sign';
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Quoted-Printable Test',
    text: 'Email with quoted-printable attachment',
    attachments: [{
      filename: 'special-chars.txt',
      content: Buffer.from(textWithSpecialChars, 'utf8'),
      contentType: 'text/plain; charset=utf-8',
      encoding: 'quoted-printable'
    }]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Quoted-printable encoding handled correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle content-disposition', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Content-Disposition Test',
    text: 'Testing attachment vs inline disposition',
    html: '<p>Image below: <img src="cid:inline-image"></p>',
    attachments: [
      {
        filename: 'attachment.txt',
        content: Buffer.from('This is an attachment'),
        contentType: 'text/plain'
        // Default disposition is 'attachment'
      },
      {
        filename: 'inline-image.png',
        content: Buffer.from('fake png data'),
        contentType: 'image/png',
        contentId: 'inline-image' // Makes it inline
      }
    ]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Content-disposition handled correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle large attachments efficiently', async () => {
  // Create a 10MB attachment
  const largeSize = 10 * 1024 * 1024;
  const largeData = crypto.randomBytes(largeSize);
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Large Attachment Test',
    text: 'Email with large attachment',
    attachments: [{
      filename: 'large-file.bin',
      content: largeData,
      contentType: 'application/octet-stream'
    }]
  });
  
  const startTime = Date.now();
  const result = await smtpClient.sendMail(email);
  const duration = Date.now() - startTime;
  
  expect(result.success).toBeTrue();
  console.log(`✅ Large attachment (${largeSize / 1024 / 1024}MB) sent in ${duration}ms`);
  console.log(`   Throughput: ${(largeSize / 1024 / 1024 / (duration / 1000)).toFixed(2)} MB/s`);
});

tap.test('CEP-03: Attachment Encoding - should handle Unicode filenames', async () => {
  const unicodeAttachments = [
    {
      filename: '文档.txt', // Chinese
      content: Buffer.from('Chinese filename test'),
      contentType: 'text/plain'
    },
    {
      filename: 'файл.txt', // Russian
      content: Buffer.from('Russian filename test'),
      contentType: 'text/plain'
    },
    {
      filename: 'ファイル.txt', // Japanese
      content: Buffer.from('Japanese filename test'),
      contentType: 'text/plain'
    },
    {
      filename: '🎉emoji🎊.txt', // Emoji
      content: Buffer.from('Emoji filename test'),
      contentType: 'text/plain'
    }
  ];
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Unicode Filenames Test',
    text: 'Testing Unicode characters in filenames',
    attachments: unicodeAttachments
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Unicode filenames encoded correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle special MIME headers', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'MIME Headers Test',
    text: 'Testing special MIME headers',
    attachments: [{
      filename: 'report.xml',
      content: Buffer.from('<?xml version="1.0"?><root>test</root>'),
      contentType: 'application/xml; charset=utf-8',
      encoding: 'base64',
      headers: {
        'Content-Description': 'Monthly Report',
        'Content-Transfer-Encoding': 'base64',
        'Content-ID': '<report-2024-01@example.com>'
      }
    }]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Special MIME headers handled correctly');
});

tap.test('CEP-03: Attachment Encoding - should handle attachment size limits', async () => {
  // Test with attachment near server limit
  const nearLimitSize = 45 * 1024 * 1024; // 45MB (near 50MB limit)
  const nearLimitData = Buffer.alloc(nearLimitSize);
  
  // Fill with some pattern to avoid compression benefits
  for (let i = 0; i < nearLimitSize; i++) {
    nearLimitData[i] = i % 256;
  }
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Near Size Limit Test',
    text: 'Testing attachment near size limit',
    attachments: [{
      filename: 'near-limit.bin',
      content: nearLimitData,
      contentType: 'application/octet-stream'
    }]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log(`✅ Attachment near size limit (${nearLimitSize / 1024 / 1024}MB) accepted`);
});

tap.test('CEP-03: Attachment Encoding - should handle mixed encoding types', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Mixed Encoding Test',
    text: 'Plain text body',
    html: '<p>HTML body with special chars: café</p>',
    attachments: [
      {
        filename: 'base64.bin',
        content: crypto.randomBytes(1024),
        contentType: 'application/octet-stream',
        encoding: 'base64'
      },
      {
        filename: 'quoted.txt',
        content: Buffer.from('Text with special chars: naïve café résumé'),
        contentType: 'text/plain; charset=utf-8',
        encoding: 'quoted-printable'
      },
      {
        filename: '7bit.txt',
        content: Buffer.from('Simple ASCII text only'),
        contentType: 'text/plain',
        encoding: '7bit'
      }
    ]
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Mixed encoding types handled correctly');
});

tap.test('cleanup - close SMTP client', async () => {
  if (smtpClient && smtpClient.isConnected()) {
    await smtpClient.close();
  }
});

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

export default tap.start();