import { tap, expect } from '@git.zone/tstest/tapbundle';
import { SpfVerifier, SpfQualifier, SpfMechanismType } from '../ts/mail/security/classes.spfverifier.js';
import { DmarcVerifier, DmarcPolicy, DmarcAlignment } from '../ts/mail/security/classes.dmarcverifier.js';
import { Email } from '../ts/mail/core/classes.email.js';

/**
 * Test email authentication systems: SPF and DMARC
 */

// SPF Verifier Tests
tap.test('SPF Verifier - should parse SPF record', async () => {
  const spfVerifier = new SpfVerifier();
  
  // Test valid SPF record parsing
  const record = 'v=spf1 a mx ip4:192.168.0.1/24 include:example.org ~all';
  const parsedRecord = spfVerifier.parseSpfRecord(record);
  
  expect(parsedRecord).toBeTruthy();
  expect(parsedRecord.version).toEqual('spf1');
  expect(parsedRecord.mechanisms.length).toEqual(5);
  
  // Check specific mechanisms
  expect(parsedRecord.mechanisms[0].type).toEqual(SpfMechanismType.A);
  expect(parsedRecord.mechanisms[0].qualifier).toEqual(SpfQualifier.PASS);
  
  expect(parsedRecord.mechanisms[1].type).toEqual(SpfMechanismType.MX);
  expect(parsedRecord.mechanisms[1].qualifier).toEqual(SpfQualifier.PASS);
  
  expect(parsedRecord.mechanisms[2].type).toEqual(SpfMechanismType.IP4);
  expect(parsedRecord.mechanisms[2].value).toEqual('192.168.0.1/24');
  
  expect(parsedRecord.mechanisms[3].type).toEqual(SpfMechanismType.INCLUDE);
  expect(parsedRecord.mechanisms[3].value).toEqual('example.org');
  
  expect(parsedRecord.mechanisms[4].type).toEqual(SpfMechanismType.ALL);
  expect(parsedRecord.mechanisms[4].qualifier).toEqual(SpfQualifier.SOFTFAIL);
  
  // Test invalid record
  const invalidRecord = 'not-a-spf-record';
  const invalidParsed = spfVerifier.parseSpfRecord(invalidRecord);
  expect(invalidParsed).toBeNull();
});

// DMARC Verifier Tests
tap.test('DMARC Verifier - should parse DMARC record', async () => {
  const dmarcVerifier = new DmarcVerifier();
  
  // Test valid DMARC record parsing
  const record = 'v=DMARC1; p=reject; sp=quarantine; pct=50; adkim=s; aspf=r; rua=mailto:dmarc@example.com';
  const parsedRecord = dmarcVerifier.parseDmarcRecord(record);
  
  expect(parsedRecord).toBeTruthy();
  expect(parsedRecord.version).toEqual('DMARC1');
  expect(parsedRecord.policy).toEqual(DmarcPolicy.REJECT);
  expect(parsedRecord.subdomainPolicy).toEqual(DmarcPolicy.QUARANTINE);
  expect(parsedRecord.pct).toEqual(50);
  expect(parsedRecord.adkim).toEqual(DmarcAlignment.STRICT);
  expect(parsedRecord.aspf).toEqual(DmarcAlignment.RELAXED);
  expect(parsedRecord.reportUriAggregate).toContain('dmarc@example.com');
  
  // Test invalid record
  const invalidRecord = 'not-a-dmarc-record';
  const invalidParsed = dmarcVerifier.parseDmarcRecord(invalidRecord);
  expect(invalidParsed).toBeNull();
});

tap.test('DMARC Verifier - should verify DMARC alignment', async () => {
  const dmarcVerifier = new DmarcVerifier();
  
  // Test email domains with DMARC alignment
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.net',
    subject: 'Test DMARC alignment',
    text: 'This is a test email'
  });
  
  // Test when both SPF and DKIM pass with alignment
  const dmarcResult = await dmarcVerifier.verify(
    email,
    { domain: 'example.com', result: true },  // SPF - aligned and passed
    { domain: 'example.com', result: true }   // DKIM - aligned and passed
  );
  
  expect(dmarcResult).toBeTruthy();
  expect(dmarcResult.spfPassed).toEqual(true);
  expect(dmarcResult.dkimPassed).toEqual(true);
  expect(dmarcResult.spfDomainAligned).toEqual(true);
  expect(dmarcResult.dkimDomainAligned).toEqual(true);
  expect(dmarcResult.action).toEqual('pass');
  
  // Test when neither SPF nor DKIM is aligned
  const dmarcResult2 = await dmarcVerifier.verify(
    email,
    { domain: 'differentdomain.com', result: true },  // SPF - passed but not aligned
    { domain: 'anotherdomain.com', result: true }     // DKIM - passed but not aligned
  );
  
  // Without a DNS manager, no DMARC record will be found
  
  expect(dmarcResult2).toBeTruthy();
  expect(dmarcResult2.spfPassed).toEqual(true);
  expect(dmarcResult2.dkimPassed).toEqual(true);
  expect(dmarcResult2.spfDomainAligned).toEqual(false);
  expect(dmarcResult2.dkimDomainAligned).toEqual(false);
  
  // Without a DMARC record, the default action is 'pass'
  expect(dmarcResult2.hasDmarc).toEqual(false);
  expect(dmarcResult2.policyEvaluated).toEqual(DmarcPolicy.NONE);
  expect(dmarcResult2.actualPolicy).toEqual(DmarcPolicy.NONE);
  expect(dmarcResult2.action).toEqual('pass');
});

tap.test('DMARC Verifier - should apply policy correctly', async () => {
  const dmarcVerifier = new DmarcVerifier();
  
  // Create test email
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.net',
    subject: 'Test DMARC policy application',
    text: 'This is a test email'
  });
  
  // Test pass action
  const passResult: any = {
    hasDmarc: true,
    spfDomainAligned: true,
    dkimDomainAligned: true,
    spfPassed: true,
    dkimPassed: true,
    policyEvaluated: DmarcPolicy.NONE,
    actualPolicy: DmarcPolicy.NONE,
    appliedPercentage: 100,
    action: 'pass',
    details: 'DMARC passed'
  };
  
  const passApplied = dmarcVerifier.applyPolicy(email, passResult);
  expect(passApplied).toEqual(true);
  expect(email.mightBeSpam).toEqual(false);
  expect(email.headers['X-DMARC-Result']).toEqual('DMARC passed');
  
  // Test quarantine action
  const quarantineResult: any = {
    hasDmarc: true,
    spfDomainAligned: false,
    dkimDomainAligned: false,
    spfPassed: false,
    dkimPassed: false,
    policyEvaluated: DmarcPolicy.QUARANTINE,
    actualPolicy: DmarcPolicy.QUARANTINE,
    appliedPercentage: 100,
    action: 'quarantine',
    details: 'DMARC failed, policy=quarantine'
  };
  
  // Reset email spam flag
  email.mightBeSpam = false;
  email.headers = {};
  
  const quarantineApplied = dmarcVerifier.applyPolicy(email, quarantineResult);
  expect(quarantineApplied).toEqual(true);
  expect(email.mightBeSpam).toEqual(true);
  expect(email.headers['X-Spam-Flag']).toEqual('YES');
  expect(email.headers['X-DMARC-Result']).toEqual('DMARC failed, policy=quarantine');
  
  // Test reject action
  const rejectResult: any = {
    hasDmarc: true,
    spfDomainAligned: false,
    dkimDomainAligned: false,
    spfPassed: false,
    dkimPassed: false,
    policyEvaluated: DmarcPolicy.REJECT,
    actualPolicy: DmarcPolicy.REJECT,
    appliedPercentage: 100,
    action: 'reject',
    details: 'DMARC failed, policy=reject'
  };
  
  // Reset email spam flag
  email.mightBeSpam = false;
  email.headers = {};
  
  const rejectApplied = dmarcVerifier.applyPolicy(email, rejectResult);
  expect(rejectApplied).toEqual(false);
  expect(email.mightBeSpam).toEqual(true);
});

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

export default tap.start();