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

/**
 * RECON mode agent — OSINT Reconnaissance.
 *
 * Performs execution engine OSINT reconnaissance against a target domain.
 * Ported from execution engine/modes/recon.py.
 *
 * @module execution-engine/modes/recon
 */

import { ModeAgentConfig, ToolRegistry } from '../framework.js';
import { OSINTValidator } from '../validators/osint.js';
import { DomainIntelligence } from '../../pipeline/osint.js';

// ---------------------------------------------------------------------------
// Tool handlers
// ---------------------------------------------------------------------------

/**
 * Resolve DNS records for a target domain.
 * @param {*} context
 * @param {Object} toolInput
 * @returns {string}
 */
export function _reconDnsLookup(context, toolInput) {
  const domain = toolInput.domain || '';
  if (!domain) {
    return "ERROR: 'domain' parameter is required.";
  }

  const result = DomainIntelligence.dnsLookup(domain);
  return JSON.stringify(result.toDict ? result.toDict() : result, null, 2);
}

/**
 * Perform WHOIS lookup for a target domain.
 * @param {*} context
 * @param {Object} toolInput
 * @returns {string}
 */
export function _reconWhoisLookup(context, toolInput) {
  const domain = toolInput.domain || '';
  if (!domain) {
    return "ERROR: 'domain' parameter is required.";
  }

  const result = DomainIntelligence.whoisLookup(domain);
  return JSON.stringify(result.toDict ? result.toDict() : result, null, 2);
}

/**
 * Store a structured JSON intelligence report in context.
 * @param {*} context
 * @param {Object} toolInput
 * @returns {string}
 */
export function _reconWriteIntelReport(context, toolInput) {
  const report = toolInput.report || '';

  if (typeof context !== 'object' || context === null) {
    return 'ERROR: Context must be a dict.';
  }

  let reportData;
  if (typeof report === 'string') {
    try {
      reportData = JSON.parse(report);
    } catch {
      reportData = report;
    }
  } else {
    reportData = report;
  }

  context.report = reportData;
  const filename = toolInput.filename || 'intel_report.json';

  return (
    `Intelligence report stored as ${filename}. ` +
    `Report is available in context['report'].`
  );
}

// ---------------------------------------------------------------------------
// Tool schemas (Anthropic format)
// ---------------------------------------------------------------------------

const _RECON_DNS_LOOKUP_SCHEMA = {
  name: 'dns_lookup',
  description:
    'Resolve DNS records for a target domain. Returns A, AAAA, MX, NS, TXT, ' +
    'CNAME, and SOA records as structured JSON.',
  input_schema: {
    type: 'object',
    properties: {
      domain: {
        type: 'string',
        description: 'Target domain to resolve (e.g. example.com)',
      },
    },
    required: ['domain'],
  },
};

const _RECON_WHOIS_LOOKUP_SCHEMA = {
  name: 'whois_lookup',
  description:
    'Perform WHOIS lookup for a target domain. Returns registration data ' +
    'including registrar, creation date, expiration date, name servers.',
  input_schema: {
    type: 'object',
    properties: {
      domain: {
        type: 'string',
        description: 'Target domain to query (e.g. example.com)',
      },
    },
    required: ['domain'],
  },
};

const _RECON_WRITE_INTEL_REPORT_SCHEMA = {
  name: 'write_intel_report',
  description:
    'Submit the completed OSINT intelligence report as JSON with required ' +
    'sections: summary, target, dns_records, whois_data, technologies, findings.',
  input_schema: {
    type: 'object',
    properties: {
      report: {
        type: 'string',
        description:
          'Full JSON intelligence report with summary, target, dns_records, ' +
          'whois_data, technologies, and findings sections.',
      },
      filename: {
        type: 'string',
        description: 'Filename for the report (e.g. example_com_intel.json)',
      },
    },
    required: ['report'],
  },
};

// ---------------------------------------------------------------------------
// System prompt template
// ---------------------------------------------------------------------------

const _RECON_SYSTEM_PROMPT = `\
You are an expert OSINT analyst and reconnaissance specialist. Your task is \
to perform passive reconnaissance on a target domain and produce a structured \
intelligence report.

## Target
Domain: {target_domain}
Description: {target_description}

## Instructions
1. Use \`dns_lookup\` to resolve DNS records for the target domain.
2. Use \`whois_lookup\` to retrieve domain registration data.
3. Analyze collected data to identify technology indicators, infrastructure, \
security posture, and attack surface.
4. Produce a structured JSON report using \`write_intel_report\`.

## Rules
- Stay PASSIVE — no active scanning, port probing, or exploitation
- Document confidence levels for all findings
- Include raw evidence supporting each finding
- Flag any privacy-sensitive data encountered
`;

// ---------------------------------------------------------------------------
// Output parser (fallback for text-based output)
// ---------------------------------------------------------------------------

/**
 * Extract JSON intelligence report from LLM text output.
 * @param {string} text
 * @returns {Object}
 */
export function _reconOutputParser(text) {
  if (!text || !text.trim()) {
    return { raw_text: text, parse_error: 'empty output' };
  }

  // Try explicit json-tagged fences first
  let matches = [...text.matchAll(/```json\s*\n(.*?)```/gs)].map(m => m[1]);
  if (matches.length > 0) {
    const jsonText = matches.join('\n');
    try { return JSON.parse(jsonText); } catch (e) {
      return { raw_text: text, parse_error: e.message };
    }
  }

  // Fall back to bare fences
  matches = [...text.matchAll(/```\s*\n(.*?)```/gs)].map(m => m[1]);
  if (matches.length > 0) {
    const jsonText = matches.join('\n');
    try { return JSON.parse(jsonText); } catch (e) {
      return { raw_text: text, parse_error: e.message };
    }
  }

  // Try parsing entire text as JSON
  try { return JSON.parse(text); } catch (e) {
    return { raw_text: text, parse_error: e.message };
  }
}

// ---------------------------------------------------------------------------
// Factory function
// ---------------------------------------------------------------------------

/**
 * Build a RECON-mode ModeAgentConfig for OSINT reconnaissance.
 * @returns {ModeAgentConfig}
 */
function _makeReconConfig() {
  const reg = new ToolRegistry();
  reg.register('dns_lookup', _RECON_DNS_LOOKUP_SCHEMA, _reconDnsLookup);
  reg.register('whois_lookup', _RECON_WHOIS_LOOKUP_SCHEMA, _reconWhoisLookup);
  reg.register('write_intel_report', _RECON_WRITE_INTEL_REPORT_SCHEMA, _reconWriteIntelReport);

  return new ModeAgentConfig({
    mode: 'RECON',
    toolRegistry: reg,
    systemPromptTemplate: _RECON_SYSTEM_PROMPT,
    validator: new OSINTValidator(),
    maxTurns: 15,
    requiresSandbox: false,
    completionCheck: null,
    outputParser: _reconOutputParser,
    outputFormat: 'json',
  });
}

// ---------------------------------------------------------------------------
// Registration function — called by runner.initModes()
// ---------------------------------------------------------------------------

/**
 * Register RECON mode with the given registerMode function.
 * @param {Function} registerMode
 */
export function register(registerMode) {
  registerMode('RECON', _makeReconConfig);
}
