import { INSTALLER_TECHNOLOGIES } from '../data/installerCatalog.js';

// Installer intelligence: infer the installer technology from a file name and
// return recommended silent install/uninstall commands plus a detection
// suggestion. Pure + table-driven, so it is fully unit-tested. Binary signature
// sniffing (reading the file) is Phase 5; this works from the name/extension.

function extensionOf(fileName = '') {
  const match = String(fileName).toLowerCase().match(/(\.[a-z0-9]+)$/);
  return match ? match[1] : '';
}

function render(template = '', { file = '', productCode = '' } = {}) {
  return String(template)
    .split('{file}').join(file)
    .split('{productCode}').join(productCode || '{productCode}');
}

function shape(tech, ctx) {
  return {
    id: tech.id,
    label: tech.label,
    install: render(tech.install, ctx),
    uninstall: render(tech.uninstall, ctx),
    psadtInstall: render(tech.psadtInstall, ctx),
    psadtUninstall: tech.psadtUninstall ? render(tech.psadtUninstall, ctx) : '',
    detection: tech.detection,
    notes: tech.notes
  };
}

export function listInstallerTechnologies() {
  return INSTALLER_TECHNOLOGIES.map(({ id, label, extensions, detection, notes }) => ({ id, label, extensions, detection, notes }));
}

// Analyze a file name. Returns the best-guess technology, a confidence level,
// and the full set of candidate technologies for that extension so the operator
// can pick when the name alone is ambiguous (common for .exe).
export function analyzeInstaller({ fileName = '', productCode = '' } = {}) {
  const ext = extensionOf(fileName);
  const lower = String(fileName).toLowerCase();
  const ctx = { file: fileName, productCode };

  const byExt = INSTALLER_TECHNOLOGIES.filter((tech) => tech.extensions.includes(ext));
  if (!byExt.length) {
    return {
      fileName,
      extension: ext,
      confidence: 'unknown',
      primary: null,
      candidates: [],
      message: ext ? `No installer technology is known for "${ext}".` : 'Provide an installer file name with an extension.'
    };
  }

  // Unique extension (.msi/.msp/.msix...) → high confidence, single technology.
  if (byExt.length === 1) {
    return { fileName, extension: ext, confidence: 'high', primary: shape(byExt[0], ctx), candidates: [shape(byExt[0], ctx)] };
  }

  // Ambiguous (.exe): try a name hint, otherwise fall back to generic EXE.
  const hinted = byExt.find((tech) => (tech.hints || []).some((hint) => lower.includes(hint)) && tech.id !== 'exe');
  const generic = byExt.find((tech) => tech.id === 'exe') || byExt[0];
  const primary = hinted || generic;
  return {
    fileName,
    extension: ext,
    confidence: hinted ? 'medium' : 'low',
    primary: shape(primary, ctx),
    // Offer all candidates (generic last) so the UI can present a picker.
    candidates: [...byExt.filter((t) => t.id !== 'exe'), ...byExt.filter((t) => t.id === 'exe')].map((t) => shape(t, ctx)),
    message: hinted
      ? `Matched "${hinted.label}" from the file name.`
      : 'Ambiguous EXE — pick the matching technology, or confirm the silent switch with the vendor.'
  };
}
