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;
let smtpClient: SmtpClient;

tap.test('setup - start SMTP server for MAIL FROM tests', async () => {
  testServer = await startTestServer({
    port: 2541,
    tlsEnabled: false,
    authRequired: false,
    size: 10 * 1024 * 1024 // 10MB size limit
  });
  
  expect(testServer.port).toEqual(2541);
});

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

tap.test('CCMD-02: MAIL FROM - should send basic MAIL FROM command', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Basic MAIL FROM Test',
    text: 'Testing basic MAIL FROM command'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.envelope?.from).toEqual('sender@example.com');
  
  console.log('✅ Basic MAIL FROM command sent successfully');
});

tap.test('CCMD-02: MAIL FROM - should handle display names correctly', async () => {
  const email = new Email({
    from: 'John Doe <john.doe@example.com>',
    to: 'Jane Smith <jane.smith@example.com>',
    subject: 'Display Name Test',
    text: 'Testing MAIL FROM with display names'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  // Envelope should contain only email address, not display name
  expect(result.envelope?.from).toEqual('john.doe@example.com');
  
  console.log('✅ Display names handled correctly in MAIL FROM');
});

tap.test('CCMD-02: MAIL FROM - should handle SIZE parameter if server supports it', async () => {
  // Send a larger email to test SIZE parameter
  const largeContent = 'x'.repeat(1000000); // 1MB of content
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'SIZE Parameter Test',
    text: largeContent
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ SIZE parameter handled for large email');
});

tap.test('CCMD-02: MAIL FROM - should handle international email addresses', async () => {
  const email = new Email({
    from: 'user@例え.jp',
    to: 'recipient@example.com',
    subject: 'International Domain Test',
    text: 'Testing international domains in MAIL FROM'
  });
  
  try {
    const result = await smtpClient.sendMail(email);
    
    if (result.success) {
      console.log('✅ International domain accepted');
      expect(result.envelope?.from).toContain('@');
    }
  } catch (error) {
    // Some servers may not support international domains
    console.log('ℹ️ Server does not support international domains');
  }
});

tap.test('CCMD-02: MAIL FROM - should handle empty return path (bounce address)', async () => {
  const email = new Email({
    from: '<>', // Empty return path for bounces
    to: 'recipient@example.com',
    subject: 'Bounce Message Test',
    text: 'This is a bounce message with empty return path'
  });
  
  try {
    const result = await smtpClient.sendMail(email);
    
    if (result.success) {
      console.log('✅ Empty return path accepted for bounce');
      expect(result.envelope?.from).toEqual('');
    }
  } catch (error) {
    console.log('ℹ️ Server rejected empty return path');
  }
});

tap.test('CCMD-02: MAIL FROM - should handle special characters in local part', async () => {
  const specialEmails = [
    'user+tag@example.com',
    'first.last@example.com',
    'user_name@example.com',
    'user-name@example.com'
  ];
  
  for (const fromEmail of specialEmails) {
    const email = new Email({
      from: fromEmail,
      to: 'recipient@example.com',
      subject: 'Special Character Test',
      text: `Testing special characters in: ${fromEmail}`
    });
    
    const result = await smtpClient.sendMail(email);
    
    expect(result.success).toBeTrue();
    expect(result.envelope?.from).toEqual(fromEmail);
    
    console.log(`✅ Special character email accepted: ${fromEmail}`);
  }
});

tap.test('CCMD-02: MAIL FROM - should reject invalid sender addresses', async () => {
  const invalidSenders = [
    'no-at-sign',
    '@example.com',
    'user@',
    'user@@example.com',
    'user@.com',
    'user@example.',
    'user with spaces@example.com'
  ];
  
  let rejectedCount = 0;
  
  for (const invalidSender of invalidSenders) {
    try {
      const email = new Email({
        from: invalidSender,
        to: 'recipient@example.com',
        subject: 'Invalid Sender Test',
        text: 'This should fail'
      });
      
      await smtpClient.sendMail(email);
    } catch (error) {
      rejectedCount++;
      console.log(`✅ Invalid sender rejected: ${invalidSender}`);
    }
  }
  
  expect(rejectedCount).toBeGreaterThan(0);
});

tap.test('CCMD-02: MAIL FROM - should handle 8BITMIME parameter', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'UTF-8 Test – with special characters',
    text: 'This email contains UTF-8 characters: 你好世界 🌍',
    html: '<p>UTF-8 content: <strong>你好世界</strong> 🌍</p>'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ 8BITMIME content handled correctly');
});

tap.test('CCMD-02: MAIL FROM - should handle AUTH parameter if authenticated', async () => {
  // Create authenticated client - auth requires TLS per RFC 8314
  const authServer = await startTestServer({
    port: 2542,
    tlsEnabled: true,
    authRequired: true
  });
  
  const authClient = createSmtpClient({
    host: authServer.hostname,
    port: authServer.port,
    secure: false,  // Use STARTTLS instead of direct TLS
    requireTLS: true,  // Require TLS upgrade
    tls: {
      rejectUnauthorized: false  // Accept self-signed cert for testing
    },
    auth: {
      user: 'testuser',
      pass: 'testpass'
    },
    connectionTimeout: 5000,
    debug: true
  });
  
  try {
    const email = new Email({
      from: 'authenticated@example.com',
      to: 'recipient@example.com',
      subject: 'AUTH Parameter Test',
      text: 'Sent with authentication'
    });
    
    const result = await authClient.sendMail(email);
    
    expect(result.success).toBeTrue();
    console.log('✅ AUTH parameter handled in MAIL FROM');
  } catch (error) {
    console.error('AUTH test error:', error);
    throw error;
  } finally {
    await authClient.close();
    await stopTestServer(authServer);
  }
});

tap.test('CCMD-02: MAIL FROM - should handle very long email addresses', async () => {
  // RFC allows up to 320 characters total (64 + @ + 255)
  const longLocal = 'a'.repeat(64);
  const longDomain = 'subdomain.' + 'a'.repeat(60) + '.example.com';
  const longEmail = `${longLocal}@${longDomain}`;
  
  const email = new Email({
    from: longEmail,
    to: 'recipient@example.com',
    subject: 'Long Email Address Test',
    text: 'Testing maximum length email addresses'
  });
  
  try {
    const result = await smtpClient.sendMail(email);
    
    if (result.success) {
      console.log('✅ Long email address accepted');
      expect(result.envelope?.from).toEqual(longEmail);
    }
  } catch (error) {
    console.log('ℹ️ Server enforces email length limits');
  }
});

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();