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 * as net from 'net';
import * as os from 'os';

let testServer: ITestServer;

tap.test('setup test SMTP server', async () => {
  testServer = await startTestServer({
    port: 2535,
    tlsEnabled: false,
    authRequired: false
  });
  expect(testServer).toBeTruthy();
  expect(testServer.port).toEqual(2535);
});

tap.test('CCM-09: Check system IPv6 support', async () => {
  const networkInterfaces = os.networkInterfaces();
  let hasIPv6 = false;
  
  for (const interfaceName in networkInterfaces) {
    const interfaces = networkInterfaces[interfaceName];
    if (interfaces) {
      for (const iface of interfaces) {
        if (iface.family === 'IPv6' && !iface.internal) {
          hasIPv6 = true;
          console.log(`Found IPv6 address: ${iface.address} on ${interfaceName}`);
        }
      }
    }
  }
  
  console.log(`System has IPv6 support: ${hasIPv6}`);
});

tap.test('CCM-09: IPv4 connection test', async () => {
  const smtpClient = createSmtpClient({
    host: '127.0.0.1', // Explicit IPv4
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  // Test connection using verify
  const verified = await smtpClient.verify();
  expect(verified).toBeTrue();
  
  console.log('Successfully connected via IPv4');
  
  await smtpClient.close();
});

tap.test('CCM-09: IPv6 connection test (if supported)', async () => {
  // Check if IPv6 is available
  const hasIPv6 = await new Promise<boolean>((resolve) => {
    const testSocket = net.createConnection({
      host: '::1',
      port: 1, // Any port, will fail but tells us if IPv6 works
      timeout: 100
    });
    
    testSocket.on('error', (err: any) => {
      // ECONNREFUSED means IPv6 works but port is closed (expected)
      // ENETUNREACH or EAFNOSUPPORT means IPv6 not available
      resolve(err.code === 'ECONNREFUSED');
    });
    
    testSocket.on('connect', () => {
      testSocket.end();
      resolve(true);
    });
  });

  if (!hasIPv6) {
    console.log('IPv6 not available on this system, skipping IPv6 tests');
    return;
  }

  // Try IPv6 connection
  const smtpClient = createSmtpClient({
    host: '::1', // IPv6 loopback
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  try {
    const verified = await smtpClient.verify();
    if (verified) {
      console.log('Successfully connected via IPv6');
      await smtpClient.close();
    } else {
      console.log('IPv6 connection failed (server may not support IPv6)');
    }
  } catch (error: any) {
    console.log('IPv6 connection failed (server may not support IPv6):', error.message);
  }
});

tap.test('CCM-09: Hostname resolution preference', async () => {
  // Test that client can handle hostnames that resolve to both IPv4 and IPv6
  const smtpClient = createSmtpClient({
    host: 'localhost', // Should resolve to both 127.0.0.1 and ::1
    port: testServer.port,
    secure: false,
    connectionTimeout: 5000,
    debug: true
  });

  const verified = await smtpClient.verify();
  expect(verified).toBeTrue();

  console.log('Successfully connected to localhost');

  await smtpClient.close();
});

tap.test('CCM-09: Happy Eyeballs algorithm simulation', async () => {
  // Test connecting to multiple addresses with preference
  const addresses = ['127.0.0.1', '::1', 'localhost'];
  const results: Array<{ address: string; time: number; success: boolean }> = [];

  for (const address of addresses) {
    const startTime = Date.now();
    const smtpClient = createSmtpClient({
      host: address,
      port: testServer.port,
      secure: false,
      connectionTimeout: 1000,
      debug: false
    });

    try {
      const verified = await smtpClient.verify();
      const elapsed = Date.now() - startTime;
      results.push({ address, time: elapsed, success: verified });
      
      if (verified) {
        await smtpClient.close();
      }
    } catch (error) {
      const elapsed = Date.now() - startTime;
      results.push({ address, time: elapsed, success: false });
    }
  }

  console.log('Connection race results:');
  results.forEach(r => {
    console.log(`  ${r.address}: ${r.success ? 'SUCCESS' : 'FAILED'} in ${r.time}ms`);
  });

  // At least one should succeed
  const successfulConnections = results.filter(r => r.success);
  expect(successfulConnections.length).toBeGreaterThan(0);
});

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

export default tap.start();