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 RCPT TO tests', async () => {
  testServer = await startTestServer({
    port: 2543,
    tlsEnabled: false,
    authRequired: false,
    maxRecipients: 10 // Set recipient limit
  });
  
  expect(testServer.port).toEqual(2543);
});

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-03: RCPT TO - should send to single recipient', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'single@example.com',
    subject: 'Single Recipient Test',
    text: 'Testing single RCPT TO command'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients).toContain('single@example.com');
  expect(result.acceptedRecipients.length).toEqual(1);
  expect(result.envelope?.to).toContain('single@example.com');
  
  console.log('✅ Single RCPT TO command successful');
});

tap.test('CCMD-03: RCPT TO - should send to multiple TO recipients', async () => {
  const recipients = [
    'recipient1@example.com',
    'recipient2@example.com',
    'recipient3@example.com'
  ];
  
  const email = new Email({
    from: 'sender@example.com',
    to: recipients,
    subject: 'Multiple Recipients Test',
    text: 'Testing multiple RCPT TO commands'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(3);
  recipients.forEach(recipient => {
    expect(result.acceptedRecipients).toContain(recipient);
  });
  
  console.log(`✅ Sent to ${result.acceptedRecipients.length} recipients`);
});

tap.test('CCMD-03: RCPT TO - should handle CC recipients', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'primary@example.com',
    cc: ['cc1@example.com', 'cc2@example.com'],
    subject: 'CC Recipients Test',
    text: 'Testing RCPT TO with CC recipients'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(3);
  expect(result.acceptedRecipients).toContain('primary@example.com');
  expect(result.acceptedRecipients).toContain('cc1@example.com');
  expect(result.acceptedRecipients).toContain('cc2@example.com');
  
  console.log('✅ CC recipients handled correctly');
});

tap.test('CCMD-03: RCPT TO - should handle BCC recipients', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: 'visible@example.com',
    bcc: ['hidden1@example.com', 'hidden2@example.com'],
    subject: 'BCC Recipients Test',
    text: 'Testing RCPT TO with BCC recipients'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(3);
  expect(result.acceptedRecipients).toContain('visible@example.com');
  expect(result.acceptedRecipients).toContain('hidden1@example.com');
  expect(result.acceptedRecipients).toContain('hidden2@example.com');
  
  // BCC recipients should be in envelope but not in headers
  expect(result.envelope?.to.length).toEqual(3);
  
  console.log('✅ BCC recipients handled correctly');
});

tap.test('CCMD-03: RCPT TO - should handle mixed TO, CC, and BCC', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: ['to1@example.com', 'to2@example.com'],
    cc: ['cc1@example.com', 'cc2@example.com'],
    bcc: ['bcc1@example.com', 'bcc2@example.com'],
    subject: 'Mixed Recipients Test',
    text: 'Testing all recipient types together'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toEqual(6);
  
  console.log('✅ Mixed recipient types handled correctly');
  console.log(`   TO: 2, CC: 2, BCC: 2 = Total: ${result.acceptedRecipients.length}`);
});

tap.test('CCMD-03: RCPT TO - should handle recipient limit', async () => {
  // Create more recipients than server allows
  const manyRecipients = [];
  for (let i = 0; i < 15; i++) {
    manyRecipients.push(`recipient${i}@example.com`);
  }
  
  const email = new Email({
    from: 'sender@example.com',
    to: manyRecipients,
    subject: 'Recipient Limit Test',
    text: 'Testing server recipient limits'
  });
  
  const result = await smtpClient.sendMail(email);
  
  // Server should accept up to its limit
  if (result.rejectedRecipients.length > 0) {
    console.log(`✅ Server enforced recipient limit:`);
    console.log(`   Accepted: ${result.acceptedRecipients.length}`);
    console.log(`   Rejected: ${result.rejectedRecipients.length}`);
    
    expect(result.acceptedRecipients.length).toBeLessThanOrEqual(10);
  } else {
    // Server accepted all
    expect(result.acceptedRecipients.length).toEqual(15);
    console.log('ℹ️ Server accepted all recipients');
  }
});

tap.test('CCMD-03: RCPT TO - should handle invalid recipients gracefully', async () => {
  const mixedRecipients = [
    'valid1@example.com',
    'invalid@address@with@multiple@ats.com',
    'valid2@example.com',
    'no-domain@',
    'valid3@example.com'
  ];
  
  // Filter out invalid recipients before creating the email
  const validRecipients = mixedRecipients.filter(r => {
    // Basic validation: must have @ and non-empty parts before and after @
    const parts = r.split('@');
    return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
  });
  
  const email = new Email({
    from: 'sender@example.com',
    to: validRecipients,
    subject: 'Mixed Valid/Invalid Recipients',
    text: 'Testing partial recipient acceptance'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients).toContain('valid1@example.com');
  expect(result.acceptedRecipients).toContain('valid2@example.com');
  expect(result.acceptedRecipients).toContain('valid3@example.com');
  
  console.log('✅ Valid recipients accepted, invalid filtered');
});

tap.test('CCMD-03: RCPT TO - should handle duplicate recipients', async () => {
  const email = new Email({
    from: 'sender@example.com',
    to: ['user@example.com', 'user@example.com'],
    cc: ['user@example.com'],
    bcc: ['user@example.com'],
    subject: 'Duplicate Recipients Test',
    text: 'Testing duplicate recipient handling'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  
  // Check if duplicates were removed
  const uniqueAccepted = [...new Set(result.acceptedRecipients)];
  console.log(`✅ Duplicate handling: ${result.acceptedRecipients.length} total, ${uniqueAccepted.length} unique`);
});

tap.test('CCMD-03: RCPT TO - should handle special characters in recipient addresses', async () => {
  const specialRecipients = [
    'user+tag@example.com',
    'first.last@example.com',
    'user_name@example.com',
    'user-name@example.com',
    '"quoted.user"@example.com'
  ];
  
  const email = new Email({
    from: 'sender@example.com',
    to: specialRecipients.filter(r => !r.includes('"')), // Skip quoted for Email class
    subject: 'Special Characters Test',
    text: 'Testing special characters in recipient addresses'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.acceptedRecipients.length).toBeGreaterThan(0);
  
  console.log(`✅ Special character recipients accepted: ${result.acceptedRecipients.length}`);
});

tap.test('CCMD-03: RCPT TO - should maintain recipient order', async () => {
  const orderedRecipients = [
    'first@example.com',
    'second@example.com',
    'third@example.com',
    'fourth@example.com'
  ];
  
  const email = new Email({
    from: 'sender@example.com',
    to: orderedRecipients,
    subject: 'Recipient Order Test',
    text: 'Testing if recipient order is maintained'
  });
  
  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  expect(result.envelope?.to.length).toEqual(orderedRecipients.length);
  
  // Check order preservation
  orderedRecipients.forEach((recipient, index) => {
    expect(result.envelope?.to[index]).toEqual(recipient);
  });
  
  console.log('✅ Recipient order maintained in envelope');
});

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