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 size limit tests', async () => {
  testServer = await startTestServer({
    port: 2573,
    tlsEnabled: false,
    authRequired: false
  });
  
  expect(testServer.port).toEqual(2573);
});

tap.test('CERR-07: Server with SIZE extension', async () => {
  // Create server that advertises SIZE extension
  const sizeServer = net.createServer((socket) => {
    socket.write('220 Size Test Server\r\n');
    
    let buffer = '';
    let inData = false;

    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 (inData) {
          if (command === '.') {
            inData = false;
            socket.write('250 OK\r\n');
          }
          continue;
        }
        
        if (command.startsWith('EHLO')) {
          socket.write('250-SIZE 1048576\r\n'); // 1MB limit
          socket.write('250 OK\r\n');
        } else if (command.startsWith('MAIL FROM')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('RCPT TO')) {
          socket.write('250 OK\r\n');
        } else if (command === 'DATA') {
          socket.write('354 Send data\r\n');
          inData = true;
        } else if (command === 'QUIT') {
          socket.write('221 Bye\r\n');
          socket.end();
        }
      }
    });
  });

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

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

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Size Test',
    text: 'Testing SIZE extension'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeTrue();
  console.log('✅ Email sent with SIZE extension support');

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

tap.test('CERR-07: Message too large at MAIL FROM', async () => {
  // Create server that rejects based on SIZE parameter
  const strictSizeServer = net.createServer((socket) => {
    socket.write('220 Strict Size Server\r\n');

    socket.on('data', (data) => {
      const command = data.toString().trim();
      
      if (command.startsWith('EHLO')) {
        socket.write('250-SIZE 1000\r\n'); // Very small limit
        socket.write('250 OK\r\n');
      } else if (command.startsWith('MAIL FROM')) {
        // Always reject with size error
        socket.write('552 5.3.4 Message size exceeds fixed maximum message size\r\n');
      } else if (command === 'QUIT') {
        socket.write('221 Bye\r\n');
        socket.end();
      }
    });
  });

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

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

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Large Message',
    text: 'This message will be rejected due to size'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeFalse();
  console.log('Actual error:', result.error?.message);
  expect(result.error?.message).toMatch(/552|size|exceeds|maximum/i);
  console.log('✅ Message size rejection at MAIL FROM handled');

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

tap.test('CERR-07: Message too large at DATA', async () => {
  // Create server that rejects after receiving data
  const dataRejectServer = net.createServer((socket) => {
    socket.write('220 Data Reject Server\r\n');
    
    let buffer = '';
    let inData = false;

    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 (inData) {
          if (command === '.') {
            inData = false;
            socket.write('552 5.3.4 Message too big for system\r\n');
          }
          continue;
        }
        
        if (command.startsWith('EHLO')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('MAIL FROM')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('RCPT TO')) {
          socket.write('250 OK\r\n');
        } else if (command === 'DATA') {
          socket.write('354 Send data\r\n');
          inData = true;
        } else if (command === 'QUIT') {
          socket.write('221 Bye\r\n');
          socket.end();
        }
      }
    });
  });

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

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

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Large Message Test',
    text: 'x'.repeat(10000) // Simulate large content
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeFalse();
  console.log('Actual error:', result.error?.message);
  expect(result.error?.message).toMatch(/552|big|size|data/i);
  console.log('✅ Message size rejection at DATA handled');

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

tap.test('CERR-07: Temporary size error - 452', async () => {
  // Create server that returns temporary size error
  const tempSizeServer = net.createServer((socket) => {
    socket.write('220 Temp Size Server\r\n');
    
    let buffer = '';
    let inData = false;

    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 (inData) {
          if (command === '.') {
            inData = false;
            socket.write('452 4.3.1 Insufficient system storage\r\n');
          }
          continue;
        }
        
        if (command.startsWith('EHLO')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('MAIL FROM')) {
          socket.write('250 OK\r\n');
        } else if (command.startsWith('RCPT TO')) {
          socket.write('250 OK\r\n');
        } else if (command === 'DATA') {
          socket.write('354 Send data\r\n');
          inData = true;
        } else if (command === 'QUIT') {
          socket.write('221 Bye\r\n');
          socket.end();
        }
      }
    });
  });

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

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

  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Temporary Size Error Test',
    text: 'Testing temporary size error'
  });

  const result = await smtpClient.sendMail(email);
  
  expect(result.success).toBeFalse();
  console.log('Actual error:', result.error?.message);
  expect(result.error?.message).toMatch(/452|storage|data/i);
  console.log('✅ Temporary size error handled');

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

tap.test('CERR-07: Normal email within size limits', 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 Size Test',
    text: 'Testing normal size email that should succeed'
  });

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

  await smtpClient.close();
});

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

export default tap.start();