import { tap, expect } from '@git.zone/tstest/tapbundle';
import { DcRouter } from '../ts/classes.dcrouter.js';

/**
 * Unit tests for socket-handler functionality
 * These tests focus on the configuration and route generation logic
 * without actually starting services on real ports
 */

let dcRouter: DcRouter;

tap.test('DNS route generation with dnsDomain', async () => {
  dcRouter = new DcRouter({
    dnsDomain: 'dns.unit.test'
  });
  
  // Test the route generation directly
  const dnsRoutes = (dcRouter as any).generateDnsRoutes();
  
  expect(dnsRoutes).toBeDefined();
  expect(dnsRoutes.length).toEqual(2);
  
  // Check /dns-query route
  const dnsQueryRoute = dnsRoutes[0];
  expect(dnsQueryRoute.name).toEqual('dns-over-https-dns-query');
  expect(dnsQueryRoute.match.ports).toEqual([443]);
  expect(dnsQueryRoute.match.domains).toEqual(['dns.unit.test']);
  expect(dnsQueryRoute.match.path).toEqual('/dns-query');
  expect(dnsQueryRoute.action.type).toEqual('socket-handler');
  expect(dnsQueryRoute.action.socketHandler).toBeDefined();
  
  // Check /resolve route
  const resolveRoute = dnsRoutes[1];
  expect(resolveRoute.name).toEqual('dns-over-https-resolve');
  expect(resolveRoute.match.ports).toEqual([443]);
  expect(resolveRoute.match.domains).toEqual(['dns.unit.test']);
  expect(resolveRoute.match.path).toEqual('/resolve');
  expect(resolveRoute.action.type).toEqual('socket-handler');
  expect(resolveRoute.action.socketHandler).toBeDefined();
});

tap.test('DNS route generation without dnsDomain', async () => {
  dcRouter = new DcRouter({
    // No dnsDomain set
  });
  
  const dnsRoutes = (dcRouter as any).generateDnsRoutes();
  
  expect(dnsRoutes).toBeDefined();
  expect(dnsRoutes.length).toEqual(0); // No routes generated
});

tap.test('Email route generation with socket-handler', async () => {
  const emailConfig = {
    ports: [25, 587, 465],
    hostname: 'mail.unit.test',
    domains: ['unit.test'],
    routes: [],
    useSocketHandler: true
  };
  
  dcRouter = new DcRouter({ emailConfig });
  
  const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig);
  
  expect(emailRoutes).toBeDefined();
  expect(emailRoutes.length).toEqual(3);
  
  // Check all routes use socket-handler
  emailRoutes.forEach((route: any) => {
    expect(route.action.type).toEqual('socket-handler');
    expect(route.action.socketHandler).toBeDefined();
    expect(typeof route.action.socketHandler).toEqual('function');
  });
  
  // Check specific ports
  const port25Route = emailRoutes.find((r: any) => r.match.ports[0] === 25);
  expect(port25Route.name).toEqual('smtp-route');
  
  const port587Route = emailRoutes.find((r: any) => r.match.ports[0] === 587);
  expect(port587Route.name).toEqual('submission-route');
  
  const port465Route = emailRoutes.find((r: any) => r.match.ports[0] === 465);
  expect(port465Route.name).toEqual('smtps-route');
});

tap.test('Email route generation with traditional forwarding', async () => {
  const emailConfig = {
    ports: [25, 587],
    hostname: 'mail.unit.test',
    domains: ['unit.test'],
    routes: [],
    useSocketHandler: false // Traditional mode
  };
  
  dcRouter = new DcRouter({ emailConfig });
  
  const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig);
  
  expect(emailRoutes).toBeDefined();
  expect(emailRoutes.length).toEqual(2);
  
  // Check all routes use forward action
  emailRoutes.forEach((route: any) => {
    expect(route.action.type).toEqual('forward');
    expect(route.action.target).toBeDefined();
    expect(route.action.target.host).toEqual('localhost');
    expect(route.action.target.port).toBeGreaterThan(10000); // Internal port
  });
});

tap.test('Email TLS modes are set correctly', async () => {
  const emailConfig = {
    ports: [25, 465],
    hostname: 'mail.unit.test',
    domains: ['unit.test'],
    routes: [],
    useSocketHandler: false
  };
  
  dcRouter = new DcRouter({ emailConfig });
  
  const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig);
  
  // Port 25 should use passthrough (STARTTLS)
  const port25Route = emailRoutes.find((r: any) => r.match.ports[0] === 25);
  expect(port25Route.action.tls.mode).toEqual('passthrough');
  
  // Port 465 should use terminate (implicit TLS)
  const port465Route = emailRoutes.find((r: any) => r.match.ports[0] === 465);
  expect(port465Route.action.tls.mode).toEqual('terminate');
  expect(port465Route.action.tls.certificate).toEqual('auto');
});

tap.test('Combined DNS and email configuration', async () => {
  dcRouter = new DcRouter({
    dnsDomain: 'dns.combined.test',
    emailConfig: {
      ports: [25],
      hostname: 'mail.combined.test',
      domains: ['combined.test'],
      routes: [],
      useSocketHandler: true
    }
  });
  
  // Generate both types of routes
  const dnsRoutes = (dcRouter as any).generateDnsRoutes();
  const emailRoutes = (dcRouter as any).generateEmailRoutes(dcRouter.options.emailConfig);
  
  // Check DNS routes
  expect(dnsRoutes.length).toEqual(2);
  dnsRoutes.forEach((route: any) => {
    expect(route.action.type).toEqual('socket-handler');
    expect(route.match.domains).toEqual(['dns.combined.test']);
  });
  
  // Check email routes
  expect(emailRoutes.length).toEqual(1);
  expect(emailRoutes[0].action.type).toEqual('socket-handler');
  expect(emailRoutes[0].match.ports).toEqual([25]);
});

tap.test('Socket handler functions are created correctly', async () => {
  dcRouter = new DcRouter({
    dnsDomain: 'dns.handler.test',
    emailConfig: {
      ports: [25, 465],
      hostname: 'mail.handler.test',
      domains: ['handler.test'],
      routes: [],
      useSocketHandler: true
    }
  });
  
  // Test DNS socket handler creation
  const dnsHandler = (dcRouter as any).createDnsSocketHandler();
  expect(dnsHandler).toBeDefined();
  expect(typeof dnsHandler).toEqual('function');
  
  // Test email socket handler creation for different ports
  const smtp25Handler = (dcRouter as any).createMailSocketHandler(25);
  expect(smtp25Handler).toBeDefined();
  expect(typeof smtp25Handler).toEqual('function');
  
  const smtp465Handler = (dcRouter as any).createMailSocketHandler(465);
  expect(smtp465Handler).toBeDefined();
  expect(typeof smtp465Handler).toEqual('function');
  
  // Handlers should be different functions
  expect(smtp25Handler).not.toEqual(smtp465Handler);
});

tap.test('stop', async () => {
  await tap.stopForcefully();
});

export default tap.start();