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';

const TEST_PORT = 2525;
let testServer: ITestServer;

// Helper function to wait for SMTP response
const waitForResponse = (socket: net.Socket, expectedCode?: string, timeout = 5000): Promise<string> => {
  return new Promise((resolve, reject) => {
    let buffer = '';
    const timer = setTimeout(() => {
      socket.removeListener('data', handler);
      reject(new Error(`Timeout waiting for ${expectedCode || 'any'} response`));
    }, timeout);
    
    const handler = (data: Buffer) => {
      buffer += data.toString();
      const lines = buffer.split('\r\n');
      
      // Check if we have a complete response
      for (const line of lines) {
        if (expectedCode) {
          if (line.startsWith(expectedCode + ' ')) {
            clearTimeout(timer);
            socket.removeListener('data', handler);
            resolve(buffer);
            return;
          }
        } else {
          // Any complete response line
          if (line.match(/^\d{3} /)) {
            clearTimeout(timer);
            socket.removeListener('data', handler);
            resolve(buffer);
            return;
          }
        }
      }
    };
    
    socket.on('data', handler);
  });
};

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

tap.test('RFC 6376 DKIM - Server accepts email with DKIM signature', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('connect', async () => {
    try {
      // Wait for greeting
      await waitForResponse(socket, '220');
      
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      await waitForResponse(socket, '250');
      
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send DATA
      socket.write('DATA\r\n');
      await waitForResponse(socket, '354');
      
      // Create email with DKIM signature
      const dkimSignature = [
        'DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;',
        '        d=example.com; s=default;',
        '        h=from:to:subject:date:message-id;',
        '        bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;',
        '        b=Kt1zLCYmUVYJKEOVL9nGF2JVPJ5/k5l6yOkNBJGCrZn4E5z9Qn7TlYrG8QfBgJ4',
        '        CzYVLjKm5xOhUoEaDzTJ1E6C9A4hL8sKfBxQjN8oWv4kP3GdE6mFqS0wKcRjT+',
        '        NxOz2VcJP4LmKjFsG8XqBhYoEfCvSr3UwNmEkP6RjT9WlQzA4kJe2VoMsJ='
      ].join('\r\n');
      
      const email = [
        `From: sender@example.com`,
        `To: recipient@example.com`,
        `Subject: DKIM RFC 6376 Compliance Test`,
        `Date: ${new Date().toUTCString()}`,
        `Message-ID: <dkim-test-${Date.now()}@example.com>`,
        dkimSignature,
        '',
        'This email tests RFC 6376 DKIM compliance.',
        'The server should properly handle DKIM signatures.',
        '.',
        ''
      ].join('\r\n');
      
      socket.write(email);
      await waitForResponse(socket, '250');
      
      console.log('Email with DKIM signature accepted');
      expect(true).toEqual(true); // Server accepts DKIM headers
      
      // Send QUIT
      socket.write('QUIT\r\n');
      await waitForResponse(socket, '221');
      
      socket.end();
      done.resolve();
    } catch (err) {
      console.error('Test error:', err);
      socket.end();
      done.reject(err);
    }
  });
  
  await done.promise;
});

tap.test('RFC 6376 DKIM - Multiple DKIM signatures', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('connect', async () => {
    try {
      // Wait for greeting
      await waitForResponse(socket, '220');
      
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      await waitForResponse(socket, '250');
      
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send DATA
      socket.write('DATA\r\n');
      await waitForResponse(socket, '354');
      
      // Email with multiple DKIM signatures (common in forwarding scenarios)
      const email = [
        `From: sender@example.com`,
        `To: recipient@example.com`,
        `Subject: Multiple DKIM Signatures Test`,
        `Date: ${new Date().toUTCString()}`,
        `Message-ID: <multi-dkim-${Date.now()}@example.com>`,
        'DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;',
        '        d=example.com; s=selector1;',
        '        h=from:to:subject:date;',
        '        bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;',
        '        b=signature1data',
        'DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple;',
        '        d=forwarder.com; s=selector2;',
        '        h=from:to:subject:date:message-id;',
        '        bh=differentbodyhash=;',
        '        b=signature2data',
        '',
        'Email with multiple DKIM signatures.',
        '.',
        ''
      ].join('\r\n');
      
      socket.write(email);
      await waitForResponse(socket, '250');
      
      console.log('Email with multiple DKIM signatures accepted');
      
      // Send QUIT
      socket.write('QUIT\r\n');
      await waitForResponse(socket, '221');
      
      socket.end();
      done.resolve();
    } catch (err) {
      console.error('Test error:', err);
      socket.end();
      done.reject(err);
    }
  });
  
  await done.promise;
});

tap.test('RFC 6376 DKIM - Various canonicalization methods', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('connect', async () => {
    try {
      // Wait for greeting
      await waitForResponse(socket, '220');
      
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      await waitForResponse(socket, '250');
      
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send DATA
      socket.write('DATA\r\n');
      await waitForResponse(socket, '354');
      
      // Test different canonicalization methods
      const email = [
        `From: sender@example.com`,
        `To: recipient@example.com`,
        `Subject: DKIM Canonicalization Test`,
        `Date: ${new Date().toUTCString()}`,
        `Message-ID: <canon-${Date.now()}@example.com>`,
        'DKIM-Signature: v=1; a=rsa-sha256; c=simple/relaxed;',
        '        d=example.com; s=default;',
        '        h=from:to:subject;',
        '        bh=bodyhash=;',
        '        b=signature',
        '',
        'Testing different canonicalization methods.',
        'Simple header canonicalization preserves whitespace.',
        'Relaxed body canonicalization normalizes whitespace.',
        '.',
        ''
      ].join('\r\n');
      
      socket.write(email);
      await waitForResponse(socket, '250');
      
      console.log('Email with different canonicalization accepted');
      
      // Send QUIT
      socket.write('QUIT\r\n');
      await waitForResponse(socket, '221');
      
      socket.end();
      done.resolve();
    } catch (err) {
      console.error('Test error:', err);
      socket.end();
      done.reject(err);
    }
  });
  
  await done.promise;
});

tap.test('RFC 6376 DKIM - Long header fields and folding', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('connect', async () => {
    try {
      // Wait for greeting
      await waitForResponse(socket, '220');
      
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      await waitForResponse(socket, '250');
      
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send DATA
      socket.write('DATA\r\n');
      await waitForResponse(socket, '354');
      
      // DKIM signature with long fields that require folding
      const longSignature = 'b=' + 'A'.repeat(200);
      
      const email = [
        `From: sender@example.com`,
        `To: recipient@example.com`,
        `Subject: DKIM Long Fields Test`,
        `Date: ${new Date().toUTCString()}`,
        `Message-ID: <long-dkim-${Date.now()}@example.com>`,
        'DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;',
        '        d=example.com; s=default; t=' + Math.floor(Date.now() / 1000) + ';',
        '        h=from:to:subject:date:message-id:content-type:mime-version;',
        '        bh=verylongbodyhashvalueherethatexceedsnormallength1234567890=;',
        '        ' + longSignature.substring(0, 70),
        '        ' + longSignature.substring(70, 140),
        '        ' + longSignature.substring(140),
        '',
        'Testing DKIM with long header fields.',
        '.',
        ''
      ].join('\r\n');
      
      socket.write(email);
      await waitForResponse(socket, '250');
      
      console.log('Email with long DKIM fields accepted');
      
      // Send QUIT
      socket.write('QUIT\r\n');
      await waitForResponse(socket, '221');
      
      socket.end();
      done.resolve();
    } catch (err) {
      console.error('Test error:', err);
      socket.end();
      done.reject(err);
    }
  });
  
  await done.promise;
});

tap.test('RFC 6376 DKIM - Authentication-Results header', async (tools) => {
  const done = tools.defer();
  
  const socket = net.createConnection({
    host: 'localhost',
    port: TEST_PORT,
    timeout: 30000
  });
  
  socket.on('error', (err) => {
    console.error('Socket error:', err);
    done.reject(err);
  });
  
  socket.on('connect', async () => {
    try {
      // Wait for greeting
      await waitForResponse(socket, '220');
      
      // Send EHLO
      socket.write('EHLO testclient\r\n');
      const ehloResponse = await waitForResponse(socket, '250');
      
      // Check if server advertises DKIM support
      const advertisesDkim = ehloResponse.toLowerCase().includes('dkim');
      console.log('Server advertises DKIM:', advertisesDkim);
      
      // Send MAIL FROM
      socket.write('MAIL FROM:<sender@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send RCPT TO
      socket.write('RCPT TO:<recipient@example.com>\r\n');
      await waitForResponse(socket, '250');
      
      // Send DATA
      socket.write('DATA\r\n');
      await waitForResponse(socket, '354');
      
      // Email to test if server adds Authentication-Results header
      const email = [
        `From: sender@example.com`,
        `To: recipient@example.com`,
        `Subject: Authentication-Results Test`,
        `Date: ${new Date().toUTCString()}`,
        `Message-ID: <auth-results-${Date.now()}@example.com>`,
        'DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;',
        '        d=example.com; s=default;',
        '        h=from:to:subject;',
        '        bh=simplehash=;',
        '        b=simplesignature',
        '',
        'Testing if server adds Authentication-Results header.',
        '.',
        ''
      ].join('\r\n');
      
      socket.write(email);
      await waitForResponse(socket, '250');
      
      console.log('Email accepted - server should process DKIM and potentially add Authentication-Results');
      
      // Send QUIT
      socket.write('QUIT\r\n');
      await waitForResponse(socket, '221');
      
      socket.end();
      done.resolve();
    } catch (err) {
      console.error('Test error:', err);
      socket.end();
      done.reject(err);
    }
  });
  
  await done.promise;
});

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

export default tap.start();