import { tap, expect } from '@git.zone/tstest/tapbundle';
import { ContentScanner, ThreatCategory } from '../ts/security/classes.contentscanner.js';
import { Email } from '../ts/mail/core/classes.email.js';

// Test instantiation
tap.test('ContentScanner - should be instantiable', async () => {
  const scanner = ContentScanner.getInstance({
    scanBody: true,
    scanSubject: true,
    scanAttachments: true
  });
  
  expect(scanner).toBeTruthy();
});

// Test singleton pattern
tap.test('ContentScanner - should use singleton pattern', async () => {
  const scanner1 = ContentScanner.getInstance();
  const scanner2 = ContentScanner.getInstance();
  
  // Both instances should be the same object
  expect(scanner1 === scanner2).toEqual(true);
});

// Test clean email can be correctly distinguished from high-risk email
tap.test('ContentScanner - should distinguish between clean and suspicious emails', async () => {
  // Create an instance with a higher minimum threat score
  const scanner = new ContentScanner({
    minThreatScore: 50 // Higher threshold to consider clean
  });
  
  // Create a truly clean email with no potentially sensitive data patterns
  const cleanEmail = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Project Update',
    text: 'The project is on track. Let me know if you have questions.',
    html: '<p>The project is on track. Let me know if you have questions.</p>'
  });
  
  // Create a highly suspicious email
  const suspiciousEmail = new Email({
    from: 'admin@bank-fake.com',
    to: 'victim@example.com',
    subject: 'URGENT: Your account needs verification now!',
    text: 'Click here to verify your account or it will be suspended: https://bit.ly/12345',
    html: '<p>Click here to verify your account or it will be suspended: <a href="https://bit.ly/12345">click here</a></p>'
  });
  
  // Test both emails
  const cleanResult = await scanner.scanEmail(cleanEmail);
  const suspiciousResult = await scanner.scanEmail(suspiciousEmail);
  
  console.log('Clean vs Suspicious results:', {
    cleanScore: cleanResult.threatScore,
    suspiciousScore: suspiciousResult.threatScore
  });
  
  // Verify the scanner can distinguish between them
  // Suspicious email should have a significantly higher score
  expect(suspiciousResult.threatScore > cleanResult.threatScore + 40).toEqual(true);
  
  // Verify clean email scans all expected elements
  expect(cleanResult.scannedElements.length > 0).toEqual(true);
});

// Test phishing detection in subject
tap.test('ContentScanner - should detect phishing in subject', async () => {
  // Create a dedicated scanner for this test
  const scanner = new ContentScanner({
    scanSubject: true,
    scanBody: true,
    scanAttachments: false,
    customRules: []
  });
  
  const email = new Email({
    from: 'security@bank-account-verify.com',
    to: 'victim@example.com',
    subject: 'URGENT: Verify your bank account details immediately',
    text: 'Your account will be suspended. Please verify your details.',
    html: '<p>Your account will be suspended. Please verify your details.</p>'
  });
  
  const result = await scanner.scanEmail(email);
  
  console.log('Phishing email scan result:', result);
  
  // We only care that it detected something suspicious
  expect(result.threatScore >= 20).toEqual(true);
  
  // Check if any threat was detected (specific type may vary)
  expect(result.threatType).toBeTruthy();
});

// Test malware indicators in body
tap.test('ContentScanner - should detect malware indicators in body', async () => {
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'invoice@company.com',
    to: 'recipient@example.com',
    subject: 'Your invoice',
    text: 'Please see the attached invoice. You need to enable macros to view this document properly.',
    html: '<p>Please see the attached invoice. You need to enable macros to view this document properly.</p>'
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType === ThreatCategory.MALWARE || result.threatType).toBeTruthy();
  expect(result.threatScore >= 30).toEqual(true);
});

// Test suspicious link detection
tap.test('ContentScanner - should detect suspicious links', async () => {
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'newsletter@example.com',
    to: 'recipient@example.com',
    subject: 'Weekly Newsletter',
    text: 'Check our latest offer at https://bit.ly/2x3F5 and https://t.co/abc123',
    html: '<p>Check our latest offer at <a href="https://bit.ly/2x3F5">here</a> and <a href="https://t.co/abc123">here</a></p>'
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType).toEqual(ThreatCategory.SUSPICIOUS_LINK);
  expect(result.threatScore >= 30).toEqual(true);
});

// Test script injection detection
tap.test('ContentScanner - should detect script injection', async () => {
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'newsletter@example.com',
    to: 'recipient@example.com',
    subject: 'Newsletter',
    text: 'Check our website',
    html: '<p>Check our website</p><script>document.cookie="session="+localStorage.getItem("token");</script>'
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType).toEqual(ThreatCategory.XSS);
  expect(result.threatScore >= 40).toEqual(true);
});

// Test executable attachment detection
tap.test('ContentScanner - should detect executable attachments', async () => {
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Software Update',
    text: 'Please install the attached software update.',
    attachments: [{
      filename: 'update.exe',
      content: Buffer.from('MZ...fake executable content...'),
      contentType: 'application/octet-stream'
    }]
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType).toEqual(ThreatCategory.EXECUTABLE);
  expect(result.threatScore >= 70).toEqual(true);
});

// Test macro document detection
tap.test('ContentScanner - should detect macro documents', async () => {
  // Create a mock Office document with macro indicators
  const fakeDocContent = Buffer.from('Document content...vbaProject.bin...Auto_Open...DocumentOpen...Microsoft VBA...');
  
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Financial Report',
    text: 'Please review the attached financial report.',
    attachments: [{
      filename: 'report.docm',
      content: fakeDocContent,
      contentType: 'application/vnd.ms-word.document.macroEnabled.12'
    }]
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType).toEqual(ThreatCategory.MALICIOUS_MACRO);
  expect(result.threatScore >= 60).toEqual(true);
});

// Test compound threat detection (multiple indicators)
tap.test('ContentScanner - should detect compound threats', async () => {
  const scanner = ContentScanner.getInstance();
  
  const email = new Email({
    from: 'security@bank-verify.com',
    to: 'victim@example.com',
    subject: 'URGENT: Verify your account details immediately',
    text: 'Your account will be suspended unless you verify your details at https://bit.ly/2x3F5',
    html: '<p>Your account will be suspended unless you verify your details <a href="https://bit.ly/2x3F5">here</a>.</p>',
    attachments: [{
      filename: 'verification.exe',
      content: Buffer.from('MZ...fake executable content...'),
      contentType: 'application/octet-stream'
    }]
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatScore > 70).toEqual(true); // Should have a high score due to multiple threats
});

// Test custom rules
tap.test('ContentScanner - should apply custom rules', async () => {
  // Create a scanner with custom rules
  const scanner = new ContentScanner({
    customRules: [
      {
        pattern: /CUSTOM_PATTERN_FOR_TESTING/,
        type: ThreatCategory.CUSTOM_RULE,
        score: 50,
        description: 'Custom pattern detected'
      }
    ]
  });
  
  const email = new Email({
    from: 'sender@example.com',
    to: 'recipient@example.com',
    subject: 'Test Custom Rule',
    text: 'This message contains CUSTOM_PATTERN_FOR_TESTING that should be detected.'
  });
  
  const result = await scanner.scanEmail(email);
  
  expect(result.isClean).toEqual(false);
  expect(result.threatType).toEqual(ThreatCategory.CUSTOM_RULE);
  expect(result.threatScore >= 50).toEqual(true);
});

// Test threat level classification
tap.test('ContentScanner - should classify threat levels correctly', async () => {
  expect(ContentScanner.getThreatLevel(10)).toEqual('none');
  expect(ContentScanner.getThreatLevel(25)).toEqual('low');
  expect(ContentScanner.getThreatLevel(50)).toEqual('medium');
  expect(ContentScanner.getThreatLevel(80)).toEqual('high');
});

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

export default tap.start();