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

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

/**
 * RESEARCHER mode handler — CVE analysis, reverse engineering, AI security.
 * Adds: vulnerabilities, techniques, research
 */
export class ResearcherHandler extends BaseHandler {
  constructor() { super('researcher'); }

  domainActions() {
    return ['vulnerabilities', 'techniques', 'research'];
  }

  describeDomain(action) {
    return {
      'vulnerabilities': 'Extract CVE references, vulnerability patterns, and exploitation vectors',
      'techniques':      'Map reverse engineering and analysis techniques with tool commands',
      'research':        'Compile research notes, references, and threat landscape context',
    }[action];
  }

  async executeDomain(command, ctx) {
    switch (command) {
      case 'vulnerabilities': return this.vulnerabilities(ctx);
      case 'techniques':      return this.techniques(ctx);
      case 'research':        return this.research(ctx);
      default: throw new Error(`Unknown RESEARCHER command: ${command}`);
    }
  }

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

    // Extract CVE references
    const cves = new Set();
    const cveRe = /CVE-\d{4}-\d{4,}/g;
    let m;
    while ((m = cveRe.exec(skill.raw))) {
      cves.add(m[0]);
    }

    // Extract CWE references
    const cwes = new Set();
    const cweRe = /CWE-\d+/g;
    while ((m = cweRe.exec(skill.raw))) {
      cwes.add(m[0]);
    }

    // Extract vulnerability tables
    const vulnTables = [];
    for (const table of skill.tables) {
      if (table.headers.some(h => /vuln|cve|cwe|weakness|flaw|bug|exploit/i.test(h))) {
        vulnTables.push({
          headers: table.headers,
          rows: table.rows.slice(0, 15),
        });
      }
    }

    const cvesList = [...cves];

    return {
      action: 'vulnerabilities',
      technique,
      mode: 'RESEARCHER',
      attackIds: skill.attackIds,
      cves: cvesList,
      cveValidation: this.validateCveIds(cvesList),
      cwes: [...cwes],
      vulnTables: vulnTables.slice(0, 5),
      status: 'vulnerabilities_complete',
    };
  }

  /** Validate CVE IDs for correct format (CVE-YYYY-NNNNN, year≥1999, 4-7 digit suffix). */
  validateCveIds(cves) {
    if (!Array.isArray(cves)) return { valid: [], invalid: [], total: 0 };
    const valid = [];
    const invalid = [];
    const cveRe = /^CVE-(\d{4})-(\d{4,7})$/;
    for (const id of cves) {
      const m = String(id).match(cveRe);
      if (m && parseInt(m[1], 10) >= 1999) { valid.push(id); } else { invalid.push(id); }
    }
    return { valid, invalid, total: cves.length };
  }

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

    // Extract analysis methods from sections
    const methods = skill.sections
      .filter(s => /method|technique|approach|analys|revers|debug|disassembl/i.test(s.title))
      .map(s => ({
        method: s.title,
        content: s.content.slice(0, 400),
      }));

    // Extract tool-specific commands
    const toolCommands = skill.codeBlocks
      .filter(b => ['bash', 'python', 'sh', 'powershell', 'gdb', 'r2'].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: 'techniques',
      technique,
      mode: 'RESEARCHER',
      attackIds: skill.attackIds,
      tools: skill.tools,
      methods: methods.slice(0, 10),
      toolCommands: toolCommands.slice(0, 15),
      status: 'techniques_complete',
    };
  }

  /** Compile research notes and context. */
  research(ctx) {
    const { skill, technique } = ctx;
    if (!skill) throw new Error('No SKILL.md found');

    // Extract references
    const refs = [];
    const urlRe = /https?:\/\/[^\s)]+/g;
    let m;
    while ((m = urlRe.exec(skill.raw))) {
      refs.push(m[0]);
    }

    // Extract key concepts
    const concepts = skill.sections
      .filter(s => /concept|background|overview|theory|fundamentals/i.test(s.title))
      .map(s => ({
        topic: s.title,
        content: s.content.slice(0, 400),
      }));

    // Extract related techniques
    const related = skill.sections
      .filter(s => /related|see.also|further|reference/i.test(s.title))
      .map(s => ({
        topic: s.title,
        content: s.content.slice(0, 300),
      }));

    return {
      action: 'research',
      technique,
      mode: 'RESEARCHER',
      attackIds: skill.attackIds,
      tools: skill.tools,
      concepts: concepts.slice(0, 5),
      references: [...new Set(refs)].slice(0, 20),
      related: related.slice(0, 5),
      status: 'research_complete',
    };
  }
}
