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

import { BaseHandler } from './base.js';

/**
 * INCIDENT mode handler — forensics & IR.
 * Adds: forensic, timeline, evidence
 */
export class IncidentHandler extends BaseHandler {
  constructor() { super('incident'); }

  domainActions() {
    return ['forensic', 'timeline', 'evidence'];
  }

  describeDomain(action) {
    return {
      'forensic': 'Extract forensic procedures and artifact collection steps',
      'timeline': 'Build investigation timeline from technique indicators',
      'evidence': 'List evidence sources, preservation steps, and chain-of-custody',
    }[action];
  }

  async executeDomain(command, ctx) {
    switch (command) {
      case 'forensic': return this.forensic(ctx);
      case 'timeline': return this.timeline(ctx);
      case 'evidence': return this.evidence(ctx);
      default: throw new Error(`Unknown INCIDENT command: ${command}`);
    }
  }

  /** Extract forensic procedures. */
  forensic(ctx) {
    const { skill, technique } = ctx;
    if (!skill) throw new Error('No SKILL.md found');

    const procedures = [];
    for (const section of skill.sections) {
      if (/forensic|collect|acqui|preserv|analyz|examin|procedur/i.test(section.title)) {
        procedures.push({
          phase: section.title,
          content: section.content.slice(0, 500),
        });
      }
    }

    // Extract forensic commands
    const commands = skill.codeBlocks
      .filter(b => ['bash', 'powershell', 'sh', 'python'].includes(b.lang))
      .map(b => ({
        lang: b.lang,
        context: b.context,
        commands: b.code.split('\n')
          .filter(l => l.trim() && !l.trim().startsWith('#'))
          .slice(0, 10),
      }));

    return {
      action: 'forensic',
      technique,
      mode: 'INCIDENT',
      attackIds: skill.attackIds,
      tools: skill.tools,
      procedures: procedures.slice(0, 10),
      commands: commands.slice(0, 15),
      status: 'forensic_complete',
    };
  }

  /** Build investigation timeline framework. */
  timeline(ctx) {
    const { skill, technique } = ctx;
    if (!skill) throw new Error('No SKILL.md found');

    // Extract timeline-relevant data from tables
    const artifacts = [];
    for (const table of skill.tables) {
      if (table.headers.some(h => /event|log|artifact|timestamp|evidence|indicator/i.test(h))) {
        artifacts.push({
          headers: table.headers,
          entries: table.rows.slice(0, 15),
        });
      }
    }

    // Extract phases from workflow sections
    const phases = skill.sections
      .filter(s => /step|phase|stage|workflow|timeline|triage|contain|eradicat|recover/i.test(s.title))
      .map(s => ({
        phase: s.title,
        summary: s.content.slice(0, 300),
      }));

    return {
      action: 'timeline',
      technique,
      mode: 'INCIDENT',
      attackIds: skill.attackIds,
      artifacts: artifacts.slice(0, 5),
      phases: phases.slice(0, 10),
      status: 'timeline_complete',
    };
  }

  /** Classify evidence sources as volatile or non-volatile. */
  classifyEvidenceType(sources) {
    if (!Array.isArray(sources)) return { volatile: [], nonVolatile: [], unclassified: [] };
    const volatileRe = /memory|ram|process|network|connection|cache|register/i;
    const nonVolatileRe = /disk|file|log|registry|image|backup|database/i;
    const volatile = [];
    const nonVolatile = [];
    const unclassified = [];
    sources.forEach((src, idx) => {
      const text = typeof src === 'string' ? src : Object.values(src || {}).join(' ');
      const isVolatile = volatileRe.test(text);
      const isNonVolatile = nonVolatileRe.test(text);
      if (isVolatile) { volatile.push(idx); }
      else if (isNonVolatile) { nonVolatile.push(idx); }
      else { unclassified.push(idx); }
    });
    return { volatile, nonVolatile, unclassified };
  }

  /** List evidence sources and preservation steps. */
  evidence(ctx) {
    const { skill, technique } = ctx;
    if (!skill) throw new Error('No SKILL.md found');

    const sources = [];
    // Extract from tables
    for (const table of skill.tables) {
      if (table.headers.some(h => /source|evidence|artifact|log|location|path/i.test(h))) {
        for (const row of table.rows) {
          sources.push(row);
        }
      }
    }

    // Extract preservation notes
    const preservation = skill.sections
      .filter(s => /preserv|chain|custody|integrity|hash|imag/i.test(s.title))
      .map(s => ({
        topic: s.title,
        content: s.content.slice(0, 300),
      }));

    return {
      action: 'evidence',
      technique,
      mode: 'INCIDENT',
      attackIds: skill.attackIds,
      tools: skill.tools,
      sources: sources.slice(0, 20),
      evidenceClassification: this.classifyEvidenceType(sources.slice(0, 20)),
      preservation: preservation.slice(0, 5),
      status: 'evidence_complete',
    };
  }
}
