import './setup.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { load } from './setup.mjs';

const { analyzeInstaller, listInstallerTechnologies } = await load('../services/installerIntelService.js');
const { buildDetectionRule } = await load('../services/detectionRuleService.js');

// --- installer detection + silent switches --------------------------------

test('MSI is detected with high confidence and product-code uninstall', () => {
  const result = analyzeInstaller({ fileName: 'ContosoVpn.msi', productCode: '{12345678-1234-1234-1234-123456789012}' });
  assert.equal(result.confidence, 'high');
  assert.equal(result.primary.id, 'msi');
  assert.ok(result.primary.install.includes('/qn'));
  assert.ok(result.primary.uninstall.includes('{12345678-1234-1234-1234-123456789012}'));
});

test('MSIX is detected from its extension', () => {
  const result = analyzeInstaller({ fileName: 'App_1.0.0.0_x64.msixbundle' });
  assert.equal(result.primary.id, 'msix');
  assert.ok(result.primary.install.includes('Add-AppxProvisionedPackage'));
});

test('EXE with a name hint matches the technology at medium confidence', () => {
  const result = analyzeInstaller({ fileName: 'app-nsis-setup.exe' });
  assert.equal(result.confidence, 'medium');
  assert.equal(result.primary.id, 'nsis');
  assert.equal(result.primary.install, '"app-nsis-setup.exe" /S');
});

test('ambiguous EXE falls back to generic and offers candidates', () => {
  const result = analyzeInstaller({ fileName: 'installer.exe' });
  assert.equal(result.confidence, 'low');
  assert.equal(result.primary.id, 'exe');
  const ids = result.candidates.map((c) => c.id);
  assert.ok(ids.includes('inno') && ids.includes('installshield'));
  assert.equal(ids[ids.length - 1], 'exe', 'generic EXE is offered last');
});

test('unknown extension reports unknown', () => {
  const result = analyzeInstaller({ fileName: 'notes.txt' });
  assert.equal(result.confidence, 'unknown');
  assert.equal(result.primary, null);
});

test('listInstallerTechnologies exposes the catalog', () => {
  const list = listInstallerTechnologies();
  assert.ok(list.find((t) => t.id === 'inno'));
  assert.ok(list.every((t) => Array.isArray(t.extensions)));
});

// --- detection rule generation --------------------------------------------

test('MSI detection maps to a product-code rule', () => {
  const rule = buildDetectionRule({ type: 'msi', productCode: '{abc}' });
  assert.equal(rule.detectionType, 'msi-product-code');
  assert.equal(rule.detectionRule, '{abc}');
});

test('file detection generates a versioned PowerShell script', () => {
  const rule = buildDetectionRule({ type: 'file', path: 'C:\\Program Files\\App\\app.exe', version: '2.0.0' });
  assert.equal(rule.detectionType, 'custom-script');
  assert.ok(rule.detectionRule.includes('Test-Path'));
  assert.ok(rule.detectionRule.includes("[version]'2.0.0'"));
  assert.ok(rule.detectionRule.includes("Write-Output 'Detected'"));
});

test('registry detection with a value comparison', () => {
  const rule = buildDetectionRule({ type: 'registry', keyPath: 'HKLM:\\SOFTWARE\\Contoso', valueName: 'Version', valueData: '2.0' });
  assert.equal(rule.detectionType, 'custom-script');
  assert.ok(rule.detectionRule.includes('HKLM:\\SOFTWARE\\Contoso'));
  assert.ok(rule.detectionRule.includes("-eq '2.0'"));
});

test('detection generator validates required inputs', () => {
  assert.throws(() => buildDetectionRule({ type: 'msi' }));
  assert.throws(() => buildDetectionRule({ type: 'file' }));
  assert.throws(() => buildDetectionRule({ type: 'bogus' }));
});
