#!/usr/bin/env tsx

/**
 * Test DNS server configuration and record registration
 */

import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as plugins from '../ts/plugins.js';

// Test DNS configuration
const testDnsConfig = {
  udpPort: 5353, // Use non-privileged port for testing
  httpsPort: 8443,
  httpsKey: './test/fixtures/test-key.pem',
  httpsCert: './test/fixtures/test-cert.pem',
  dnssecZone: 'test.example.com',
  records: [
    { name: 'test.example.com', type: 'A', value: '192.168.1.1' },
    { name: 'mail.test.example.com', type: 'A', value: '192.168.1.2' },
    { name: 'test.example.com', type: 'MX', value: '10 mail.test.example.com' },
    { name: 'test.example.com', type: 'TXT', value: 'v=spf1 a:mail.test.example.com ~all' },
    { name: 'test.example.com', type: 'NS', value: 'ns1.test.example.com' },
    { name: 'ns1.test.example.com', type: 'A', value: '192.168.1.1' }
  ]
};

tap.test('DNS server configuration - should extract records correctly', async () => {
  const { records, ...dnsServerOptions } = testDnsConfig;
  
  expect(dnsServerOptions.udpPort).toEqual(5353);
  expect(dnsServerOptions.httpsPort).toEqual(8443);
  expect(dnsServerOptions.dnssecZone).toEqual('test.example.com');
  expect(records).toBeArray();
  expect(records.length).toEqual(6);
});

tap.test('DNS server configuration - should handle record parsing', async () => {
  const parseDnsRecordData = (type: string, value: string): any => {
    switch (type) {
      case 'A':
        return value;
      case 'MX':
        const [priority, exchange] = value.split(' ');
        return { priority: parseInt(priority), exchange };
      case 'TXT':
        return value;
      case 'NS':
        return value;
      default:
        return value;
    }
  };
  
  // Test A record parsing
  const aRecord = parseDnsRecordData('A', '192.168.1.1');
  expect(aRecord).toEqual('192.168.1.1');
  
  // Test MX record parsing
  const mxRecord = parseDnsRecordData('MX', '10 mail.test.example.com');
  expect(mxRecord).toHaveProperty('priority', 10);
  expect(mxRecord).toHaveProperty('exchange', 'mail.test.example.com');
  
  // Test TXT record parsing
  const txtRecord = parseDnsRecordData('TXT', 'v=spf1 a:mail.test.example.com ~all');
  expect(txtRecord).toEqual('v=spf1 a:mail.test.example.com ~all');
});

tap.test('DNS server configuration - should group records by domain', async () => {
  const records = testDnsConfig.records;
  const recordsByDomain = new Map<string, typeof records>();
  
  for (const record of records) {
    const pattern = record.name.includes('*') ? record.name : `*.${record.name}`;
    if (!recordsByDomain.has(pattern)) {
      recordsByDomain.set(pattern, []);
    }
    recordsByDomain.get(pattern)!.push(record);
  }
  
  // Check grouping
  expect(recordsByDomain.size).toBeGreaterThan(0);
  
  // Verify each group has records
  for (const [pattern, domainRecords] of recordsByDomain) {
    expect(domainRecords.length).toBeGreaterThan(0);
    console.log(`Pattern: ${pattern}, Records: ${domainRecords.length}`);
  }
});

tap.test('DNS server configuration - should extract unique record types', async () => {
  const records = testDnsConfig.records;
  const recordTypes = [...new Set(records.map(r => r.type))];
  
  expect(recordTypes).toContain('A');
  expect(recordTypes).toContain('MX');
  expect(recordTypes).toContain('TXT');
  expect(recordTypes).toContain('NS');
  
  console.log('Unique record types:', recordTypes.join(', '));
});

tap.test('DNS server - mock handler registration', async () => {
  // Mock DNS server for testing
  const mockDnsServer = {
    handlers: new Map<string, any>(),
    registerHandler: function(pattern: string, types: string[], handler: Function) {
      this.handlers.set(pattern, { types, handler });
      console.log(`Registered handler for pattern: ${pattern}, types: ${types.join(', ')}`);
    }
  };
  
  // Simulate record registration
  const records = testDnsConfig.records;
  const recordsByDomain = new Map<string, typeof records>();
  
  for (const record of records) {
    const pattern = record.name.includes('*') ? record.name : `*.${record.name}`;
    if (!recordsByDomain.has(pattern)) {
      recordsByDomain.set(pattern, []);
    }
    recordsByDomain.get(pattern)!.push(record);
  }
  
  // Register handlers
  for (const [domainPattern, domainRecords] of recordsByDomain) {
    const recordTypes = [...new Set(domainRecords.map(r => r.type))];
    mockDnsServer.registerHandler(domainPattern, recordTypes, (question: any) => {
      const matchingRecord = domainRecords.find(
        r => r.name === question.name && r.type === question.type
      );
      return matchingRecord || null;
    });
  }
  
  expect(mockDnsServer.handlers.size).toBeGreaterThan(0);
});

tap.start({
  throwOnError: true
});