#!/usr/bin/env node

/**
 * Config-Audit Drift CLI
 * Compare current configuration against a saved baseline.
 * Usage:
 *   node drift-cli.mjs <path> --save [--name my-baseline]
 *   node drift-cli.mjs <path> [--baseline my-baseline] [--json]
 *   node drift-cli.mjs --list
 * Zero external dependencies.
 */

import { resolve } from 'node:path';
import { runAllScanners } from './scan-orchestrator.mjs';
import { diffEnvelopes, formatDiffReport } from './lib/diff-engine.mjs';
import { saveBaseline, loadBaseline, listBaselines } from './lib/baseline.mjs';
import { humanizeFindings } from './lib/humanizer.mjs';

async function main() {
  const args = process.argv.slice(2);
  let targetPath = '.';
  let baselineName = 'default';
  let save = false;
  let list = false;
  let jsonMode = false;
  let rawMode = false;
  let includeGlobal = false;

  for (let i = 0; i < args.length; i++) {
    if (args[i] === '--save') {
      save = true;
    } else if (args[i] === '--name' && args[i + 1]) {
      baselineName = args[++i];
    } else if (args[i] === '--baseline' && args[i + 1]) {
      baselineName = args[++i];
    } else if (args[i] === '--list') {
      list = true;
    } else if (args[i] === '--json') {
      jsonMode = true;
    } else if (args[i] === '--raw') {
      rawMode = true;
    } else if (args[i] === '--global') {
      includeGlobal = true;
    } else if (!args[i].startsWith('-')) {
      targetPath = args[i];
    }
  }

  // --- List mode ---
  if (list) {
    const result = await listBaselines();
    if (jsonMode || rawMode) {
      process.stdout.write(JSON.stringify(result, null, 2) + '\n');
    } else {
      if (result.baselines.length === 0) {
        process.stderr.write('No baselines saved.\n');
        process.stderr.write('Save one with: node drift-cli.mjs <path> --save\n');
      } else {
        process.stderr.write('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
        process.stderr.write(' Saved Baselines\n');
        process.stderr.write('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n');
        for (const b of result.baselines) {
          process.stderr.write(` ${b.name.padEnd(20)} ${b.findingCount} findings  ${b.savedAt}\n`);
        }
        process.stderr.write('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
      }
    }
    process.exit(0);
  }

  // --- Save mode ---
  if (save) {
    if (!jsonMode && !rawMode) {
      process.stderr.write(`Config-Audit Drift CLI v2.1.0\n`);
      process.stderr.write(`Saving baseline "${baselineName}" for ${resolve(targetPath)}\n\n`);
    }

    const envelope = await runAllScanners(targetPath, { includeGlobal, humanizedProgress: !jsonMode && !rawMode });
    const result = await saveBaseline(envelope, baselineName);

    if (jsonMode || rawMode) {
      process.stdout.write(JSON.stringify({ saved: true, name: result.name, path: result.path }, null, 2) + '\n');
    } else {
      process.stderr.write(`\nBaseline "${result.name}" saved to ${result.path}\n`);
      process.stderr.write(`Findings: ${envelope.aggregate.total_findings}\n`);
    }
    process.exit(0);
  }

  // --- Drift mode (default) ---
  if (!jsonMode && !rawMode) {
    process.stderr.write(`Config-Audit Drift CLI v2.1.0\n`);
    process.stderr.write(`Target: ${resolve(targetPath)}\n`);
    process.stderr.write(`Baseline: ${baselineName}\n\n`);
  }

  // Load baseline
  const baseline = await loadBaseline(baselineName);
  if (!baseline) {
    if (jsonMode || rawMode) {
      process.stdout.write(JSON.stringify({ error: `Baseline "${baselineName}" not found. Save one with --save.` }, null, 2) + '\n');
    } else {
      process.stderr.write(`Baseline "${baselineName}" not found.\n`);
      process.stderr.write(`Save one first: node drift-cli.mjs <path> --save\n`);
    }
    process.exit(1);
  }

  // Run current scan
  const current = await runAllScanners(targetPath, {
    includeGlobal,
    humanizedProgress: !jsonMode && !rawMode,
  });

  // Diff
  const diff = diffEnvelopes(baseline, current);

  if (jsonMode || rawMode) {
    // --json and --raw both write the raw v5.0.0-shape diff (byte-identical).
    process.stdout.write(JSON.stringify(diff, null, 2) + '\n');
  } else {
    // Default mode: humanize finding-bearing diff fields before report rendering.
    const humanizedDiff = {
      ...diff,
      newFindings: humanizeFindings(diff.newFindings || []),
      resolvedFindings: humanizeFindings(diff.resolvedFindings || []),
      unchangedFindings: humanizeFindings(diff.unchangedFindings || []),
      movedFindings: humanizeFindings(diff.movedFindings || []),
    };
    const report = formatDiffReport(humanizedDiff);
    process.stderr.write('\n' + report + '\n');
  }

  // Exit code: 0=stable/improving, 1=degrading
  if (diff.summary.trend === 'degrading') process.exit(1);
  process.exit(0);
}

// Only run CLI if invoked directly
const isDirectRun = process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname);
if (isDirectRun) {
  main().catch(err => {
    process.stderr.write(`Fatal: ${err.message}\n`);
    process.exit(3);
  });
}
