// Copyright (c) 2026 defconxt. All rights reserved.
// Licensed under AGPL-3.0 — see LICENSE file for details.
// NERF is a trademark of defconxt.

/**
 * command-handlers.js — Standalone handler functions for NERF slash commands.
 *
 * Two kinds of commands end up here:
 *
 * 1. **Prompt-template commands** (engage, resume, export, brief, report):
 *    These have .md files in src/resources/extensions/nerf/prompts/ and
 *    work by loading the template, substituting $ARGUMENTS, and injecting
 *    the result as a prompt into the agent session.
 *
 * 2. **Direct-handler commands** (status, quick):
 *    These execute logic directly without LLM involvement.
 *
 * The agent-repl.js dispatcher calls these based on COMMAND_REGISTRY type.
 */

import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';

// ---------------------------------------------------------------------------
// Engagement-state & dispatch helpers (restored from execution-engine)
// ---------------------------------------------------------------------------
import { readState, engagementCost } from './execution-engine/engagement.js';
import { readLock, autoLoop } from './execution-engine/dispatch.js';

// ---------------------------------------------------------------------------
// Notification helper (stdout-based, replaces ctx.ui.notify for standalone)
// ---------------------------------------------------------------------------

const LEVEL_PREFIX = {
  info: '\x1b[36mℹ\x1b[0m',
  warn: '\x1b[33m⚠\x1b[0m',
  error: '\x1b[31m✗\x1b[0m',
};

/**
 * Print a styled notification to stdout. Replaces pi ctx.ui.notify.
 * @param {string} message
 * @param {'info'|'warn'|'error'} [level='info']
 */
function notify(message, level = 'info') {
  const prefix = LEVEL_PREFIX[level] || LEVEL_PREFIX.info;
  console.log(`${prefix} ${message}`);
}

// ---------------------------------------------------------------------------
// Direct Handler: status
// ---------------------------------------------------------------------------

/**
 * Display the engagement progress dashboard.
 * No LLM call needed: reads .nerf/ state and prints to stdout.
 *
 * @param {string} args - unused
 */
export async function handleStatus(args) {

  const state = readState();
  const lines = [];

  lines.push('─── NERF Status ───');
  lines.push(`Active Engagement: ${state.activeEngagement || 'None'}`);
  lines.push(`Phase: ${state.phase || 'idle'}`);

  if (state.activeEngagement) {
    try {
      const cost = engagementCost(state.activeEngagement);
      lines.push(`Cost: $${cost.totalCost.toFixed(4)} (${cost.totalInputTokens} in, ${cost.totalOutputTokens} out)`);
    } catch {
      // Cost tracking may not be available
    }

    // Show campaigns if engagement dir exists
    const engDir = join('.nerf', 'engagements', state.activeEngagement);
    const campaignsDir = join(engDir, 'campaigns');
    if (existsSync(campaignsDir)) {
      const { readdirSync } = await import('node:fs');
      const campaigns = readdirSync(campaignsDir)
        .filter(d => /^C\d{2}$/.test(d))
        .sort();
      if (campaigns.length > 0) {
        lines.push(`Campaigns: ${campaigns.length}`);
        for (const cid of campaigns) {
          const planPath = join(campaignsDir, cid, `${cid}-PLAN.md`);
          if (existsSync(planPath)) {
            const plan = readFileSync(planPath, 'utf-8');
            const titleMatch = plan.match(/^#\s+(.+)/m);
            const title = titleMatch ? titleMatch[1] : cid;
            lines.push(`  ${cid}: ${title}`);
          } else {
            lines.push(`  ${cid}: (no plan)`);
          }
        }
      }
    }

    // Show engagement file excerpt if it exists
    const engPath = join('.nerf', 'ENGAGEMENT.md');
    if (existsSync(engPath)) {
      const content = readFileSync(engPath, 'utf-8');
      const missionMatch = content.match(/^MISSION\s*[:\-—]\s*(.+)/m);
      if (missionMatch) {
        lines.push(`Mission: ${missionMatch[1].trim()}`);
      }
    }
  }

  lines.push('─────────────────────');
  console.log(lines.join('\n'));
}

// ---------------------------------------------------------------------------
// Direct Handler: quick
// ---------------------------------------------------------------------------

/**
 * Execute a quick task with NERF guarantees, no engagement overhead.
 * Injects the task description as a prompt with quick-task framing.
 *
 * @param {string} args - task description
 * @param {object} session - pi agent session
 */
export async function handleQuick(args, session) {
  const task = (args || '').trim();
  if (!task) {
    console.error('Usage: /nerf:quick <task description>');
    return;
  }

  const quickPrompt = [
    'Execute the following security task with NERF guarantees.',
    'No engagement overhead: no .nerf/ state, no campaigns, no cost tracking.',
    'Apply the appropriate NERF mode based on the task content.',
    'Provide structured output following NERF output standards.',
    '',
    `Task: ${task}`,
  ].join('\n');

  await session.prompt(quickPrompt);
}

// ---------------------------------------------------------------------------
// Prompt-Template Handler (generic)
// ---------------------------------------------------------------------------

/**
 * Generic handler for prompt-template commands.
 * Loads the .md template, substitutes $ARGUMENTS, and injects as a prompt.
 *
 * @param {string} commandName - command name (e.g. 'engage')
 * @param {string} args - user arguments
 * @param {object} session - pi agent session
 */
export async function handlePromptTemplate(commandName, args, session) {
  const { loadCommandTemplate, substituteArgs } = await import('./command-router.js');

  try {
    const template = loadCommandTemplate(commandName);
    const injectedPrompt = substituteArgs(template, args);
    await session.prompt(injectedPrompt);
  } catch (err) {
    console.error(`Failed to load template for ${commandName}: ${err.message}`);
  }
}

// ---------------------------------------------------------------------------
// Convenience wrappers for prompt-template commands
// ---------------------------------------------------------------------------

/** Start a new engagement via the engage.md template. */
export async function handleEngage(args, session) {
  return handlePromptTemplate('engage', args, session);
}

/** Resume engagement via the resume.md template. */
export async function handleResume(args, session) {
  return handlePromptTemplate('resume', args, session);
}

/**
 * Export engagement report: parses .nerf/ENGAGEMENT.md, selects a matching
 * template, renders to markdown, and optionally converts to PDF/DOCX via pandoc.
 *
 * Usage: /nerf:export [format] [--type template_name]
 *   format: md (default), pdf, docx
 *   --type: override template selection (pentest, audit, threat-model, compliance, ir)
 *
 * @param {string} args - format and options
 * @param {object} [session] - pi agent session (unused)
 */
export async function handleExport(args, session) {
  const { parseEngagement, renderReport, listTemplates } = await import('./export/template-renderer.js');
  const { exportToPdf, exportToDocx, exportToMarkdown, exportToHtml, checkPandoc } = await import('./export/report-exporter.js');

  // Parse arguments
  const tokens = (args || '').trim().split(/\s+/).filter(Boolean);
  let format = 'md';
  let templateOverride = null;

  for (let i = 0; i < tokens.length; i++) {
    const tok = tokens[i].toLowerCase();
    if (tok === '--type' && tokens[i + 1]) {
      templateOverride = tokens[++i].toLowerCase();
    } else if (['pdf', 'docx', 'md', 'html'].includes(tok)) {
      format = tok;
    }
  }

  // Locate engagement file
  const engagementPath = join(process.cwd(), '.nerf', 'ENGAGEMENT.md');
  if (!existsSync(engagementPath)) {
    notify('No engagement found. Run /nerf:engage or cd to the project directory.', 'error');
    return;
  }

  // Parse engagement data
  let engagementData;
  try {
    engagementData = parseEngagement(engagementPath);
  } catch (err) {
    notify(`Failed to parse engagement: ${err.message}`, 'error');
    return;
  }

  // Detect template from engagement type or override
  const available = listTemplates();
  let templateName = templateOverride;

  if (!templateName) {
    // Infer from engagement_type field
    const engType = (engagementData.engagement_type || '').toLowerCase();
    if (engType.includes('pentest') || engType.includes('penetration')) {
      templateName = 'pentest';
    } else if (engType.includes('audit') || engType.includes('compliance')) {
      templateName = 'audit';
    } else if (engType.includes('threat') && engType.includes('model')) {
      templateName = 'threat-model';
    } else if (engType.includes('incident') || engType.includes('ir')) {
      templateName = 'ir';
    } else if (engType.includes('compliance')) {
      templateName = 'compliance';
    } else {
      // Default to pentest template
      templateName = 'pentest';
    }
  }

  if (!available.includes(templateName)) {
    notify(`Template "${templateName}" not found. Available: ${available.join(', ')}`, 'error');
    return;
  }

  // Render report
  let reportMarkdown;
  try {
    reportMarkdown = renderReport(templateName, engagementData);
  } catch (err) {
    notify(`Failed to render report: ${err.message}`, 'error');
    return;
  }

  // Generate output filename
  const dateStr = new Date().toISOString().slice(0, 10);
  const nerfDir = join(process.cwd(), '.nerf');
  let baseName = `REPORT-${dateStr}`;
  let mdOutputPath = join(nerfDir, `${baseName}.md`);

  // Avoid overwriting: append counter if file exists
  let counter = 1;
  while (existsSync(mdOutputPath)) {
    counter++;
    mdOutputPath = join(nerfDir, `${baseName}-${counter}.md`);
  }

  // Write markdown report
  writeFileSync(mdOutputPath, reportMarkdown, 'utf-8');

  const findingCount = (engagementData.findings || []).length;

  // Convert if requested
  if (format === 'pdf' || format === 'docx') {
    const pandoc = checkPandoc();
    if (!pandoc) {
      notify(`Markdown report saved: ${mdOutputPath}`, 'info');
      notify(`pandoc is not installed: ${format.toUpperCase()} conversion skipped. Install pandoc to enable.`, 'warn');
      notify(`Template: ${templateName} | Findings: ${findingCount}`, 'info');
      return;
    }

    try {
      const ext = format === 'pdf' ? '.pdf' : '.docx';
      const convertedPath = mdOutputPath.replace(/\.md$/, ext);

      if (format === 'pdf') {
        const result = exportToPdf(mdOutputPath, convertedPath, {
          title: engagementData.engagement_name || 'Security Report',
        });
        notify(`PDF report exported: ${result.outputPath} (engine: ${result.engine})`, 'info');
      } else {
        const result = exportToDocx(mdOutputPath, convertedPath, {
          title: engagementData.engagement_name || 'Security Report',
        });
        notify(`DOCX report exported: ${result.outputPath}`, 'info');
      }
    } catch (err) {
      notify(`${format.toUpperCase()} conversion failed: ${err.message}`, 'error');
      notify(`Markdown report saved: ${mdOutputPath}`, 'info');
    }
  } else if (format === 'html') {
    try {
      const convertedPath = mdOutputPath.replace(/\.md$/, '.html');
      const result = exportToHtml(mdOutputPath, convertedPath, {
        title: engagementData.engagement_name || 'Security Report',
      });
      const mode = result.selfContained ? 'self-contained' : 'basic (raw markdown)';
      notify(`HTML report exported: ${result.outputPath} (${mode})`, 'info');
    } catch (err) {
      notify(`HTML conversion failed: ${err.message}`, 'error');
      notify(`Markdown report saved: ${mdOutputPath}`, 'info');
    }
  } else {
    notify(`Report exported: ${mdOutputPath}`, 'info');
  }

  notify(`Template: ${templateName} | Findings: ${findingCount} | Format: ${format}`, 'info');
}

/** Full target briefing via the brief.md template. */
export async function handleBrief(args, session) {
  return handlePromptTemplate('brief', args, session);
}

/** Generate engagement report via the report.md template. */
export async function handleReport(args, session) {
  return handlePromptTemplate('report', args, session);
}

// ---------------------------------------------------------------------------
// Auto-mode state
// ---------------------------------------------------------------------------

/** @type {AbortController|null} */
let autoAbortController = null;

// ---------------------------------------------------------------------------
// Direct Handler: auto
// ---------------------------------------------------------------------------

/**
 * Enter autonomous mode: research, plan, execute, verify, repeat.
 * Checks for an active engagement, then starts the auto loop from
 * the auto-mode runtime's dispatch module.
 *
 * @param {string} args - unused
 * @param {object} session - pi agent session (unused by auto loop itself, but kept for API consistency)
 */
export async function handleAuto(args, session) {
  const state = readState();

  if (!state.activeEngagement) {
    notify('No active engagement. Use /nerf:engage first.', 'warn');
    return;
  }

  if (autoAbortController) {
    notify('Auto mode already running. Use /nerf:stop to halt.', 'warn');
    return;
  }

  autoAbortController = new AbortController();
  notify(`Starting auto mode for ${state.activeEngagement}...`);

  try {
    const result = await autoLoop({
      signal: autoAbortController.signal,
      onDispatch: (unit) => {
        notify(`Dispatching: ${unit.eid}/${unit.cid}/${unit.tid}`);
      },
      onComplete: (unit, res) => {
        const status = res.success ? '✓' : '✗';
        notify(`${status} ${unit.tid} (${res.durationMs || 0}ms)`, res.success ? 'info' : 'warn');
      },
      onStop: (reason) => {
        notify(`Auto mode stopped: ${reason}`);
      },
    });

    notify(
      `Auto mode complete: ${result.completed}/${result.dispatched} tasks, reason: ${result.reason}`,
    );
  } catch (err) {
    notify(`Auto mode error: ${err.message}`, 'error');
  } finally {
    autoAbortController = null;
  }
}

// ---------------------------------------------------------------------------
// Direct Handler: stop
// ---------------------------------------------------------------------------

/**
 * Gracefully stop autonomous mode by signaling the abort controller.
 * The auto loop finishes its current task before exiting.
 *
 * @param {string} args - unused
 */
export async function handleStop(args) {
  if (!autoAbortController) {
    notify('Auto mode is not running.');
    return;
  }
  autoAbortController.abort();
  notify('Stopping auto mode (will finish current task)...');
}

// ---------------------------------------------------------------------------
// Direct Handler: discuss
// ---------------------------------------------------------------------------

/**
 * Discuss architecture/tactics alongside auto mode.
 * Injects the topic as a prompt with full engagement context.
 *
 * @param {string} args - discussion topic
 * @param {object} session - pi agent session
 */
export async function handleDiscuss(args, session) {
  const topic = (args || '').trim();
  if (!topic) {
    notify('Usage: /nerf:discuss <topic>', 'warn');
    return;
  }

  const state = readState();

  const engContext = state.activeEngagement
    ? `Active engagement: ${state.activeEngagement}, phase: ${state.phase}`
    : 'No active engagement';

  const discussPrompt = [
    `Discuss the following topic with full NERF context. (${engContext})`,
    '',
    `Topic: ${topic}`,
  ].join('\n');

  await session.prompt(discussPrompt);
}

// ---------------------------------------------------------------------------
// Direct Handler: steer
// ---------------------------------------------------------------------------

/**
 * Hard-steer plan documents during execution.
 * Appends the steering instruction to .nerf/OVERRIDES.md (or DECISIONS.md
 * if no OVERRIDES.md pattern is established) so the next dispatched task
 * picks it up.
 *
 * @param {string} args - steering instruction
 */
export async function handleSteer(args) {
  const instruction = (args || '').trim();
  if (!instruction) {
    notify('Usage: /nerf:steer <steering instruction>', 'warn');
    return;
  }

  const state = readState();
  if (!state.activeEngagement) {
    notify('No active engagement to steer.', 'warn');
    return;
  }

  const overridesPath = join('.nerf', 'OVERRIDES.md');
  const existing = existsSync(overridesPath)
    ? readFileSync(overridesPath, 'utf-8')
    : '# NERF Overrides\n';
  const ts = new Date().toISOString().slice(0, 19);
  writeFileSync(overridesPath, `${existing}\n- [${ts}] STEER: ${instruction}\n`, 'utf-8');

  // Also append to DECISIONS.md for the append-only audit trail
  const decPath = join('.nerf', 'DECISIONS.md');
  if (existsSync(decPath)) {
    const decContent = readFileSync(decPath, 'utf-8');
    writeFileSync(decPath, `${decContent}\n- [${ts}] STEER: ${instruction}\n`, 'utf-8');
  }

  notify(`Steering recorded: ${instruction}\nWill apply to next dispatched task.`);
}

// ---------------------------------------------------------------------------
// Direct Handler: queue
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// Direct Handler: setup-hooks
// ---------------------------------------------------------------------------

/**
 * Install/reinstall NERF hooks into Claude Code settings.
 * Registers statusline (Notification), context monitor (PostToolUse),
 * and pre-commit security scan (PreCommit) hooks.
 *
 * @param {string} args - unused
 */
export async function handleSetupHooks(args) {
  const { existsSync: exists, readFileSync: readF, writeFileSync: writeF, mkdirSync } = await import('node:fs');
  const { resolve } = await import('node:path');
  const { fileURLToPath } = await import('node:url');

  // Resolve hooks directory relative to this module
  const thisFile = fileURLToPath(import.meta.url);
  const projectRoot = resolve(thisFile, '..', '..', '..');
  const hooksDir = join(projectRoot, 'hooks');

  // Claude Code hooks go in .claude/settings.local.json
  const settingsPath = join('.claude', 'settings.local.json');
  mkdirSync('.claude', { recursive: true });

  let settings = {};
  if (exists(settingsPath)) {
    try { settings = JSON.parse(readF(settingsPath, 'utf-8')); } catch { settings = {}; }
  }
  if (!settings.hooks) settings.hooks = {};

  const installed = [];

  // Statusline hook (Notification)
  const statuslinePath = exists(join(hooksDir, 'nerf-statusline.cjs'))
    ? join(hooksDir, 'nerf-statusline.cjs')
    : null;
  if (statuslinePath) {
    if (!settings.hooks.Notification) settings.hooks.Notification = [];
    const existing = settings.hooks.Notification.find(h => h.command?.includes('nerf-statusline'));
    if (!existing) {
      settings.hooks.Notification.push({ type: 'command', command: `node ${statuslinePath}`, timeout: 5000 });
    }
    installed.push('nerf-statusline (Notification)');
  }

  // Context monitor hook (PostToolUse)
  const contextMonitorPath = exists(join(hooksDir, 'nerf-context-monitor.cjs'))
    ? join(hooksDir, 'nerf-context-monitor.cjs')
    : null;
  if (contextMonitorPath) {
    if (!settings.hooks.PostToolUse) settings.hooks.PostToolUse = [];
    const existing = settings.hooks.PostToolUse.find(h => h.command?.includes('nerf-context-monitor'));
    if (!existing) {
      settings.hooks.PostToolUse.push({ type: 'command', command: `node ${contextMonitorPath}`, timeout: 5000 });
    }
    installed.push('nerf-context-monitor (PostToolUse)');
  }

  // Pre-commit security scan (PreCommit)
  const precommitPath = exists(join(hooksDir, 'nerf-precommit-scan.cjs'))
    ? join(hooksDir, 'nerf-precommit-scan.cjs')
    : null;
  if (precommitPath) {
    if (!settings.hooks.PreCommit) settings.hooks.PreCommit = [];
    const existing = settings.hooks.PreCommit.find(h => h.command?.includes('nerf-precommit-scan'));
    if (!existing) {
      settings.hooks.PreCommit.push({ type: 'command', command: `node ${precommitPath}`, timeout: 10000 });
    }
    installed.push('nerf-precommit-scan (PreCommit)');
  }

  writeF(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
  notify(
    installed.length
      ? `Installed hooks:\n${installed.map(h => `  ✓ ${h}`).join('\n')}\n\nWritten to ${settingsPath}`
      : 'No hook files found in hooks/ directory.',
    installed.length ? 'info' : 'warn',
  );
}

// ---------------------------------------------------------------------------
// Direct Handler: update
// ---------------------------------------------------------------------------

/**
 * Check for updates and upgrade NERF via npm.
 */
export async function handleUpdate() {
  const { execSync } = await import('node:child_process');
  const { readFileSync: readF } = await import('node:fs');
  const { fileURLToPath } = await import('node:url');
  const { resolve } = await import('node:path');

  try {
    const thisFile = fileURLToPath(import.meta.url);
    const pkgPath = resolve(thisFile, '..', '..', '..', 'package.json');
    const current = JSON.parse(readF(pkgPath, 'utf-8')).version;
    notify(`Current version: ${current}\nChecking npm...`);

    const latest = execSync('npm view @defconxt/nerf version', {
      encoding: 'utf-8',
      timeout: 10000,
    }).trim();

    if (latest === current) {
      notify(`Already on latest: ${current}`);
    } else {
      notify(`Update available: ${current} -> ${latest}\nRun: npm install -g @defconxt/nerf`);
    }
  } catch (err) {
    notify(`Update check failed: ${err.message}`, 'warn');
  }
}

// ---------------------------------------------------------------------------
// Direct Handler: keys
// ---------------------------------------------------------------------------

/**
 * API key manager: runs doctor checks and shows API-key-related results.
 */
export async function handleKeys() {
  try {
    const { handleDoctor: runDoctor } = await import('./gateway/commands.js');
    const result = await runDoctor();
    const apiChecks = (result?.checks || []).filter(
      c => c.name?.toLowerCase().includes('key') || c.name?.toLowerCase().includes('api'),
    );
    if (apiChecks.length) {
      console.log(apiChecks.map(c => `${c.status === 'ok' ? '✓' : '✗'} ${c.name}: ${c.detail}`).join('\n'));
    } else {
      notify('No API key checks found. Run /nerf:doctor for full diagnostics.');
    }
  } catch (err) {
    notify(`Key check failed: ${err.message}`, 'error');
  }
}

// ---------------------------------------------------------------------------
// Direct Handler: logs
// ---------------------------------------------------------------------------

/**
 * Browse recent activity, debug, and metrics logs from .nerf/activity/.
 */
export async function handleLogs() {
  const { existsSync: exists, readdirSync } = await import('node:fs');
  const logsDir = join('.nerf', 'activity');
  if (!exists(logsDir)) {
    notify('No activity logs found.');
    return;
  }
  const files = readdirSync(logsDir).sort().slice(-10);
  if (files.length === 0) {
    notify('No activity logs found.');
    return;
  }
  console.log(`Recent activity (last ${files.length}):\n${files.map(f => `  ${f}`).join('\n')}`);
}

// ---------------------------------------------------------------------------
// Direct Handler: forensics-debug
// ---------------------------------------------------------------------------

/**
 * Full-access debugger for auto-mode failure investigation.
 * Shows state, lock status, cost, recent activity, metrics, and decisions.
 *
 * @param {string} args - unused
 */
export async function handleForensicsDebug(args) {

  const sections = [];

  // State
  const state = readState();
  sections.push(`── State ──\nActive: ${state.activeEngagement || 'None'}\nPhase: ${state.phase}`);

  // Lock status (crash detection)
  const lock = readLock();
  if (lock) {
    sections.push(`⚠ Stale Lock Detected\n${JSON.stringify(lock, null, 2)}\nThis indicates a previous auto-mode session crashed.`);
  } else {
    sections.push('Lock Status: Clean (no stale lock).');
  }

  // Cost
  if (state.activeEngagement) {
    try {
      const cost = engagementCost(state.activeEngagement);
      sections.push(`Cost: $${cost.totalCost.toFixed(4)} (${cost.entries} entries, ${cost.totalInputTokens} in, ${cost.totalOutputTokens} out)`);
    } catch { /* cost tracking may not be available */ }
  }

  // Recent activity
  const activityDir = join('.nerf', 'activity');
  if (existsSync(activityDir)) {
    const { readdirSync } = await import('node:fs');
    const files = readdirSync(activityDir).sort().slice(-5);
    sections.push(`Recent Activity:\n${files.map(f => `  ${f}`).join('\n') || '  (none)'}`);
  }

  // Metrics
  const metricsPath = join('.nerf', 'metrics.json');
  if (existsSync(metricsPath)) {
    try {
      const metrics = JSON.parse(readFileSync(metricsPath, 'utf-8'));
      const last5 = (Array.isArray(metrics) ? metrics : []).slice(-5);
      if (last5.length) {
        sections.push(`Recent Metrics (last ${last5.length}):\n${last5.map(m => `  ${m.unit}: ${m.model} $${(m.cost || 0).toFixed(4)}`).join('\n')}`);
      }
    } catch { /* ignore */ }
  }

  // Decisions
  const decPath = join('.nerf', 'DECISIONS.md');
  if (existsSync(decPath)) {
    const content = readFileSync(decPath, 'utf-8');
    if (content.length > 50) {
      sections.push(`Decisions (excerpt):\n${content.slice(0, 1500)}`);
    }
  }

  console.log(sections.join('\n\n'));
}

// ---------------------------------------------------------------------------
// Direct Handler: doctor
// ---------------------------------------------------------------------------

/**
 * Run NERF diagnostics. Delegates to gateway/commands.js handleDoctor.
 */
export async function handleDoctorCmd() {
  try {
    const { handleDoctor: runDoctor } = await import('./gateway/commands.js');
    const result = await runDoctor();
    const checks = result?.checks || [];
    const ok = checks.filter(c => c.status === 'ok').length;
    const missing = checks.filter(c => c.status !== 'ok').length;

    console.log(`── NERF Doctor ──`);
    console.log(`${ok} OK, ${missing} issues\n`);
    for (const c of checks) {
      const icon = c.status === 'ok' ? '✓' : '✗';
      console.log(`  ${icon} ${c.name}: ${c.detail}`);
    }
  } catch (err) {
    notify(`Doctor failed: ${err.message}`, 'error');
  }
}

// ---------------------------------------------------------------------------
// Direct Handler: bare /nerf
// ---------------------------------------------------------------------------

/**
 * Bare /nerf command: show a status summary.
 * Equivalent to handleStatus, but called when user types just "/nerf".
 */
export async function handleNerfBare(args, session) {
  // Show status summary, then pass through to session if args provided
  await handleStatus(args);
  if ((args || '').trim()) {
    await session.prompt(args);
  }
}

// ---------------------------------------------------------------------------
// Direct Handler: queue
// ---------------------------------------------------------------------------

/**
 * Queue future campaigns for the active engagement.
 * With no args, displays the current queue. With args, appends to .nerf/QUEUE.md.
 *
 * @param {string} args - campaign description (empty to show queue)
 */
export async function handleQueue(args) {
  const state = readState();

  if (!state.activeEngagement) {
    notify('No active engagement. Use /nerf:engage first.', 'warn');
    return;
  }

  const campaign = (args || '').trim();
  const queuePath = join('.nerf', 'QUEUE.md');

  if (!campaign) {
    // Show queue
    if (existsSync(queuePath)) {
      console.log(readFileSync(queuePath, 'utf-8'));
    } else {
      notify('Queue is empty.');
    }
    return;
  }

  // Append to queue
  const existing = existsSync(queuePath)
    ? readFileSync(queuePath, 'utf-8')
    : '# NERF Queue\n\n';
  const ts = new Date().toISOString().slice(0, 19);
  writeFileSync(queuePath, `${existing}\n- [${ts}] ${campaign}\n`, 'utf-8');
  notify(`Queued: ${campaign}`);
}
