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

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

/**
 * RED mode handler — offensive security.
 * Adds: generate (attack commands, payloads), attack-path, ttps
 */
// Static ATT&CK technique → tactic mapping (70+ common techniques)
const TECHNIQUE_TACTIC_MAP = {
  T1001: 'command-and-control', T1003: 'credential-access', T1005: 'collection',
  T1007: 'discovery', T1010: 'discovery', T1011: 'exfiltration',
  T1012: 'discovery', T1016: 'discovery', T1018: 'discovery',
  T1020: 'exfiltration', T1021: 'lateral-movement', T1027: 'defense-evasion',
  T1033: 'discovery', T1036: 'defense-evasion', T1037: 'persistence',
  T1039: 'collection', T1040: 'credential-access', T1041: 'exfiltration',
  T1046: 'discovery', T1047: 'execution', T1048: 'exfiltration',
  T1049: 'discovery', T1053: 'execution', T1055: 'defense-evasion',
  T1056: 'collection', T1057: 'discovery', T1059: 'execution',
  T1068: 'privilege-escalation', T1069: 'discovery', T1070: 'defense-evasion',
  T1071: 'command-and-control', T1072: 'lateral-movement', T1074: 'collection',
  T1078: 'defense-evasion', T1080: 'lateral-movement', T1082: 'discovery',
  T1083: 'discovery', T1087: 'discovery', T1090: 'command-and-control',
  T1091: 'lateral-movement', T1095: 'command-and-control', T1098: 'persistence',
  T1102: 'command-and-control', T1104: 'command-and-control', T1105: 'command-and-control',
  T1106: 'execution', T1110: 'credential-access', T1111: 'credential-access',
  T1112: 'defense-evasion', T1113: 'collection', T1114: 'collection',
  T1115: 'collection', T1119: 'collection', T1120: 'discovery',
  T1123: 'collection', T1124: 'discovery', T1125: 'collection',
  T1127: 'defense-evasion', T1129: 'execution', T1132: 'command-and-control',
  T1133: 'persistence', T1134: 'defense-evasion', T1135: 'discovery',
  T1136: 'persistence', T1137: 'persistence', T1140: 'defense-evasion',
  T1176: 'persistence', T1185: 'collection', T1187: 'credential-access',
  T1189: 'initial-access', T1190: 'initial-access', T1195: 'initial-access',
  T1197: 'defense-evasion', T1199: 'initial-access', T1200: 'initial-access',
  T1201: 'discovery', T1202: 'defense-evasion', T1203: 'execution',
  T1204: 'execution', T1205: 'defense-evasion', T1210: 'lateral-movement',
  T1211: 'defense-evasion', T1213: 'collection', T1218: 'defense-evasion',
  T1219: 'command-and-control', T1220: 'defense-evasion',
  T1221: 'defense-evasion', T1222: 'defense-evasion',
  T1486: 'impact', T1489: 'impact', T1490: 'impact',
  T1491: 'impact', T1496: 'impact', T1498: 'impact',
  T1499: 'impact', T1529: 'impact',
  T1543: 'persistence', T1546: 'persistence', T1547: 'persistence',
  T1548: 'privilege-escalation', T1550: 'defense-evasion',
  T1552: 'credential-access', T1553: 'defense-evasion',
  T1555: 'credential-access', T1556: 'credential-access',
  T1557: 'credential-access', T1558: 'credential-access',
  T1559: 'execution', T1560: 'collection',
  T1562: 'defense-evasion', T1563: 'lateral-movement',
  T1564: 'defense-evasion', T1565: 'impact',
  T1566: 'initial-access', T1567: 'exfiltration',
  T1568: 'command-and-control', T1569: 'execution',
  T1570: 'lateral-movement', T1571: 'command-and-control',
  T1572: 'command-and-control', T1573: 'command-and-control',
  T1574: 'persistence', T1578: 'defense-evasion',
};

// Tactic → kill chain phase mapping
const TACTIC_PHASE_MAP = {
  'reconnaissance': 'reconnaissance',
  'resource-development': 'weaponization',
  'initial-access': 'delivery',
  'execution': 'exploitation',
  'persistence': 'installation',
  'privilege-escalation': 'exploitation',
  'defense-evasion': 'exploitation',
  'credential-access': 'exploitation',
  'discovery': 'exploitation',
  'lateral-movement': 'exploitation',
  'collection': 'actions-on-objectives',
  'command-and-control': 'command-and-control',
  'exfiltration': 'actions-on-objectives',
  'impact': 'actions-on-objectives',
};

export class RedHandler extends BaseHandler {
  constructor() { super('red'); }

  domainActions() {
    return ['generate', 'attack-path', 'ttps'];
  }

  describeDomain(action) {
    return {
      'generate':    'Generate attack commands and payloads from SKILL.md patterns',
      'attack-path': 'Map attack paths with ATT&CK technique chain',
      'ttps':        'Extract TTPs with MITRE ATT&CK mappings',
    }[action];
  }

  async executeDomain(command, ctx) {
    switch (command) {
      case 'generate':    return this.generate(ctx);
      case 'attack-path': return this.attackPath(ctx);
      case 'ttps':        return this.ttps(ctx);
      default: throw new Error(`Unknown RED command: ${command}`);
    }
  }

  /** Generate attack commands from code blocks. */
  generate(ctx) {
    const source = ctx.apiRef || ctx.skill;
    if (!source) throw new Error('No source material found');

    const attackLangs = ['bash', 'powershell', 'python', 'sh', 'cmd', 'text'];
    const commands = source.codeBlocks
      .filter(b => attackLangs.includes(b.lang))
      .map(b => ({
        lang: b.lang,
        context: b.context,
        commands: b.code.split('\n')
          .filter(l => l.trim() && !l.trim().startsWith('#') && !l.trim().startsWith('//'))
          .map(l => l.trim()),
      }))
      .filter(b => b.commands.length > 0);

    const target = ctx.flags.target || 'unspecified';

    return {
      action: 'generate',
      technique: ctx.technique,
      mode: 'RED',
      target,
      attackIds: source.attackIds,
      tools: source.tools,
      commandGroups: commands.slice(0, 20),
      totalCommands: commands.reduce((n, g) => n + g.commands.length, 0),
      warning: 'Authorized testing only. Verify scope before execution.',
      tactics: this.classifyAttackTactic(source.attackIds),
      status: 'generate_complete',
    };
  }

  /** Map attack paths from technique content. */
  attackPath(ctx) {
    const { skill, technique } = ctx;
    if (!skill) throw new Error('No SKILL.md found');

    // Extract attack path patterns from content
    const paths = [];
    const pathRe = /(?:→|->|==>|leads to|then|next)/gi;
    for (const section of skill.sections) {
      if (/path|chain|flow|step|workflow|kill.chain/i.test(section.title)) {
        paths.push({
          phase: section.title,
          content: section.content.slice(0, 300),
        });
      }
    }

    // Extract from code blocks with arrow patterns
    for (const block of skill.codeBlocks) {
      if (pathRe.test(block.code)) {
        paths.push({
          phase: block.context || 'attack-flow',
          content: block.code.slice(0, 300),
        });
      }
    }

    return {
      action: 'attack-path',
      technique,
      mode: 'RED',
      attackIds: skill.attackIds,
      paths: paths.slice(0, 10),
      detectionOpportunities: this.extractDetectionNotes(skill),
      status: 'attack_path_complete',
    };
  }

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

    const ttps = skill.attackIds.map(id => ({
      id,
      technique: ctx.technique,
      tools: skill.tools,
    }));

    // Cross-reference with tables that have ATT&CK column
    for (const table of skill.tables) {
      const attackCol = table.headers.find(h => /att&ck|mitre|technique/i.test(h));
      if (attackCol) {
        for (const row of table.rows) {
          const desc = row[table.headers.find(h => /description|name|action/i.test(h))] || '';
          if (row[attackCol]) {
            ttps.push({
              id: row[attackCol],
              description: desc,
              technique: ctx.technique,
            });
          }
        }
      }
    }

    return {
      action: 'ttps',
      technique,
      mode: 'RED',
      ttps: this.dedup(ttps, 'id'),
      tactics: this.classifyAttackTactic(skill.attackIds),
      detectionOpportunities: this.extractDetectionNotes(skill),
      status: 'ttps_complete',
    };
  }

  /** PURPLE layer — every RED output includes detection opportunities. */
  extractDetectionNotes(skill) {
    const notes = [];
    for (const section of skill.sections) {
      if (/detect|monitor|alert|log|hunt|blue|defend/i.test(section.title)) {
        notes.push({
          area: section.title,
          summary: section.content.slice(0, 200),
        });
      }
    }
    return notes.slice(0, 5);
  }

  /** Classify ATT&CK technique IDs to tactic names and kill chain phases. */
  classifyAttackTactic(attackIds) {
    if (!Array.isArray(attackIds)) return [];
    return attackIds.map(id => {
      const baseId = String(id).replace(/\.\d+$/, '');
      const tactic = TECHNIQUE_TACTIC_MAP[baseId] || 'unknown';
      const phase = TACTIC_PHASE_MAP[tactic] || 'unknown';
      return { id, tactic, phase };
    });
  }

  dedup(arr, key) {
    const seen = new Set();
    return arr.filter(item => {
      if (seen.has(item[key])) return false;
      seen.add(item[key]);
      return true;
    });
  }
}
