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 { Email } from '../../../ts/mail/core/classes.email.js';
import * as net from 'net';

let testServer: ITestServer;

tap.test('setup - start SMTP server for rate limiting tests', async () => {
  testServer = await startTestServer({
    port: 2578,
    tlsEnabled: false,
    authRequired: false
  });
  
  expect(testServer.port).toEqual(2578);
});

tap.test('CERR-08: Server rate limiting - 421 too many connections', async () => {
  // Create server that immediately rejects with rate limit
  const rateLimitServer = net.createServer((socket) => {
    socket.write('421 4.7.0 Too many connections, please try again later\r\n');
    socket.end();
  });

  await new Promise<void>((resolve) => {
    rateLimitServer.listen(2579, () => resolve());
  });

  const smtpClient = await createSmtpClient({
    host: '127.0.0.1',
    port: 2579,
    secure: false,
    connectionTimeout: 5000
  });

  const result = await smtpClient.verify();
  
  expect(result).toBeFalse();
  console.log('✅ 421 rate limit response handled');

  await smtpClient.close();
  await new Promise<void>((resolve) => {
    rateLimitServer.close(() => resolve());
  });
});

tap.test('CERR-08: Message rate limiting - 452', async () => {
  // Create server that rate limits at MAIL FROM
  const messageRateServer = net.createServer((socket) => {
    socket.write('220 Message Rate Server\r\n');
    
    let buffer = '';

    socket.on('data', (data) => {
      buffer += data.toString();
      
      let lines = buffer.split('\r\n');
      buffer = lines.pop() || '';
      
      for (const line of lines) {
        const command = line.trim();
        if (!command) continue;
        
        if (command.startsWith('EHLO')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('MAIL FROM')) {
          socket.write('452 4.3.2 Too many messages sent, please try later\r\n');
        } else if (command === 'QUIT') {
          socket.write('221 Bye\r\n');
          socket.end();
        }
      }
    });
  });

  await new Promise<void>((resolve) => {
    messageRateServer.listen(2580, () => resolve());
  });

  const smtpClient = await createSmtpClient({
    host: '127.0.0.1',
    port: 2580,
    secure: false,
    connectionTimeout: 5000
  });

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Rate Limit Test',
    text: 'Testing rate limiting'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeFalse();
  console.log('Actual error:', result.error?.message);
  expect(result.error?.message).toMatch(/452|many|messages|rate/i);
  console.log('✅ 452 message rate limit handled');

  await smtpClient.close();
  await new Promise<void>((resolve) => {
    messageRateServer.close(() => resolve());
  });
});

tap.test('CERR-08: User rate limiting - 550', async () => {
  // Create server that permanently blocks user
  const userRateServer = net.createServer((socket) => {
    socket.write('220 User Rate Server\r\n');
    
    let buffer = '';

    socket.on('data', (data) => {
      buffer += data.toString();
      
      let lines = buffer.split('\r\n');
      buffer = lines.pop() || '';
      
      for (const line of lines) {
        const command = line.trim();
        if (!command) continue;
        
        if (command.startsWith('EHLO')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('MAIL FROM')) {
          if (command.includes('blocked@')) {
            socket.write('550 5.7.1 User sending rate exceeded\r\n');
          } else {
            socket.write('250 OK\r\n');
          }
        } else if (command.startsWith('RCPT TO')) {
          socket.write('250 OK\r\n');
        } else if (command === 'QUIT') {
          socket.write('221 Bye\r\n');
          socket.end();
        }
      }
    });
  });

  await new Promise<void>((resolve) => {
    userRateServer.listen(2581, () => resolve());
  });

  const smtpClient = await createSmtpClient({
    host: '127.0.0.1',
    port: 2581,
    secure: false,
    connectionTimeout: 5000
  });

  const email = new Email({
    from: 'blocked@example.com',
    to: 'recipient@example.com',
    subject: 'User Rate Test',
    text: 'Testing user rate limiting'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeFalse();
  console.log('Actual error:', result.error?.message);
  expect(result.error?.message).toMatch(/550|rate|exceeded/i);
  console.log('✅ 550 user rate limit handled');

  await smtpClient.close();
  await new Promise<void>((resolve) => {
    userRateServer.close(() => resolve());
  });
});

tap.test('CERR-08: Connection throttling - delayed response', async () => {
  // Create server that delays responses to simulate throttling
  const throttleServer = net.createServer((socket) => {
    // Delay initial greeting
    setTimeout(() => {
      socket.write('220 Throttle Server\r\n');
    }, 100);
    
    let buffer = '';

    socket.on('data', (data) => {
      buffer += data.toString();
      
      let lines = buffer.split('\r\n');
      buffer = lines.pop() || '';
      
      for (const line of lines) {
        const command = line.trim();
        if (!command) continue;
        
        // Add delay to all responses
        setTimeout(() => {
          if (command.startsWith('EHLO')) {
            socket.write('250 OK\r\n');
          } else if (command === 'QUIT') {
            socket.write('221 Bye\r\n');
            socket.end();
          } else {
            socket.write('250 OK\r\n');
          }
        }, 50);
      }
    });
  });

  await new Promise<void>((resolve) => {
    throttleServer.listen(2582, () => resolve());
  });

  const smtpClient = await createSmtpClient({
    host: '127.0.0.1',
    port: 2582,
    secure: false,
    connectionTimeout: 5000
  });

  const startTime = Date.now();
  const result = await smtpClient.verify();
  const duration = Date.now() - startTime;
  
  expect(result).toBeTrue();
  console.log(`✅ Throttled connection succeeded in ${duration}ms`);

  await smtpClient.close();
  await new Promise<void>((resolve) => {
    throttleServer.close(() => resolve());
  });
});

tap.test('CERR-08: Normal email without rate limiting', async () => {
  // Test successful email send with working server
  const smtpClient = await createSmtpClient({
    host: testServer.hostname,
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000
  });

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Normal Test',
    text: 'Testing normal operation without rate limits'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Normal email sent successfully');

  await smtpClient.close();
});

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

export default tap.start();