/**
 * NERF Security Tools — 10 native security tools for the nerf runtime.
 *
 * Each tool delegates to NERF's gateway/commands.js handlers. The handlers
 * are lazy-loaded from cli/lib/ via a known relative path from the extension
 * directory to the repo root.
 *
 * Tools: scan, review, compliance, osint, memory, benchmark, lookup,
 *        techdetect, decode, dirprobe
 */
import { Type } from "@sinclair/typebox";
import { resolve, join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { existsSync } from "node:fs";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
import { homedir } from "node:os";
// ---------------------------------------------------------------------------
// Path resolver — finds cli/lib/ via known relative path from this extension
// ---------------------------------------------------------------------------
/**
 * Resolve cli/lib/ path. Checks multiple locations because pi copies
 * extensions to ~/.nerf/agent/extensions/ at runtime, breaking
 * __dirname-relative resolution.
 */
function resolveCliLib() {
    const candidates = [];
    // From __dirname (works in repo dev and global install dist/)
    candidates.push(resolve(__dirname, "..", "..", "..", "..", "cli", "lib"));
    // From the running binary
    if (process.argv[1]) {
        const binDir = dirname(resolve(process.argv[1]));
        candidates.push(resolve(binDir, "..", "cli", "lib"));
        candidates.push(resolve(binDir, "cli", "lib"));
    }
    // Common global install paths
    candidates.push("/usr/lib/node_modules/@defconxt/nerf/cli/lib");
    candidates.push("/usr/local/lib/node_modules/@defconxt/nerf/cli/lib");
    const home = homedir();
    candidates.push(join(home, ".npm-global", "lib", "node_modules", "@defconxt", "nerf", "cli", "lib"));
    for (const candidate of candidates) {
        if (existsSync(join(candidate, "gateway", "commands.js"))) {
            return candidate;
        }
    }
    return resolve(__dirname, "..", "..", "..", "..", "cli", "lib");
}
// ---------------------------------------------------------------------------
// Gateway bridge — lazy-loads NERF's command handlers
// ---------------------------------------------------------------------------
let _gateway = null;
async function gateway() {
    if (!_gateway) {
        const gatewayPath = join(resolveCliLib(), "gateway", "commands.js");
        if (existsSync(gatewayPath)) {
            _gateway = await import(gatewayPath);
        }
        if (!_gateway) {
            throw new Error("NERF gateway not found at " + gatewayPath);
        }
    }
    return _gateway;
}
async function callHandler(handlerName, args) {
    const gw = await gateway();
    const fn = gw[handlerName];
    if (!fn)
        throw new Error(`NERF handler '${handlerName}' not found`);
    try {
        const result = await fn(args);
        return typeof result === "string" ? result : JSON.stringify(result, null, 2);
    }
    catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        return `Error in ${handlerName}: ${msg}`;
    }
}
// ---------------------------------------------------------------------------
// Knowledge Store bridge — lazy-loads NERF's FTS5 knowledge index
// ---------------------------------------------------------------------------
let _knowledgeStore = null;
export async function knowledgeStore() {
    if (_knowledgeStore)
        return _knowledgeStore;
    const dbPath = join(process.env.NERF_HOME || process.env.NERF_HOME || join(homedir(), ".nerf"), "knowledge", "index.db");
    if (!existsSync(dbPath))
        return null;
    const storePath = join(resolveCliLib(), "knowledge", "store.js");
    if (existsSync(storePath)) {
        try {
            const mod = await import(storePath);
            _knowledgeStore = new mod.KnowledgeStore(dbPath);
            return _knowledgeStore;
        }
        catch {
            /* index not ready */
        }
    }
    return null;
}
// ---------------------------------------------------------------------------
// Recon tools bridge
// ---------------------------------------------------------------------------
let _recon = null;
async function recon() {
    if (!_recon) {
        const p = join(resolveCliLib(), "tools", "recon.js");
        if (existsSync(p))
            _recon = await import(p);
    }
    return _recon;
}
// ---------------------------------------------------------------------------
// Tool Registration
// ---------------------------------------------------------------------------
export function registerNerfTools(pi) {
    pi.registerTool({
        name: "scan",
        label: "Security Scan",
        description: "Run a vulnerability scan against a target. Uses Nuclei templates for CVEs, " +
            "misconfigurations, exposures, and tech detection. Can also ingest SARIF reports.",
        promptSnippet: "Run a vulnerability scan against a target",
        promptGuidelines: [
            "Use scan when the user wants to find vulnerabilities in a website, API, or domain.",
            "Requires nuclei to be installed (optional dependency).",
            "Pass sarif_file to analyze an existing SARIF report instead of running a live scan.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            target: Type.String({
                description: "Target URL or domain (e.g. https://example.com)",
            }),
            templates: Type.Optional(Type.String({
                description: "Template filter: cves, misconfigurations, exposures, technologies",
            })),
            severity: Type.Optional(Type.String({
                description: "Minimum severity: info, low, medium, high, critical",
            })),
            sarif_file: Type.Optional(Type.String({
                description: "Path to SARIF JSON file to analyze instead of live scan",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            if (params.sarif_file) {
                return {
                    content: [
                        {
                            type: "text",
                            text: await callHandler("handleSarif", {
                                input: params.sarif_file,
                            }),
                        },
                    ],
                    details: { mode: "sarif" },
                };
            }
            return {
                content: [
                    { type: "text", text: await callHandler("handleScan", params) },
                ],
                details: { target: params.target },
            };
        },
    });
    pi.registerTool({
        name: "review",
        label: "Security Review",
        description: "Security-focused code review. Uses a 3-layer engine: blind-hunter, " +
            "edge-case hunter, and defense-in-depth analysis.",
        promptSnippet: "Security code review with multi-layer engine",
        promptGuidelines: [
            "Use review for security-focused code review of files, diffs, or staged changes.",
            "Set layers to 'panel' for the full 3-layer analysis, or 'single' for quick review.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            target: Type.String({
                description: "File path, git ref (e.g. 'HEAD~1'), or 'staged'",
            }),
            focus: Type.Optional(Type.String({
                description: "Focus: security (default), auth, crypto, injection, all",
            })),
            layers: Type.Optional(Type.String({
                description: "'single' (default) or 'panel' for full 3-layer review",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const handler = params.layers === "panel" ? "handlePanel" : "handleReview";
            return {
                content: [
                    {
                        type: "text",
                        text: await callHandler(handler, {
                            ...params,
                            focus: params.focus || "security",
                        }),
                    },
                ],
                details: { target: params.target },
            };
        },
    });
    pi.registerTool({
        name: "compliance",
        label: "Compliance Assessment",
        description: "Assess compliance against 39 security frameworks: NIST 800-53, CIS Controls, " +
            "SOC 2, HIPAA, GDPR, PCI DSS, ISO 27001, FedRAMP, CMMC, and more.",
        promptSnippet: "Compliance assessment against security frameworks",
        promptGuidelines: [
            "Use compliance when the user asks about regulatory requirements or framework alignment.",
            "Supports 39 frameworks with 1,151+ controls.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            framework: Type.String({
                description: "Framework: nist-800-53, cis-controls, soc2, hipaa, gdpr, pci-dss, iso-27001, fedramp, cmmc",
            }),
            scope: Type.Optional(Type.String({
                description: "Scope filter: specific control family or domain",
            })),
            format: Type.Optional(Type.String({
                description: "Output: summary (default), detailed, csv, json",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            return {
                content: [
                    {
                        type: "text",
                        text: await callHandler("handleCompliance", {
                            ...params,
                            format: params.format || "summary",
                        }),
                    },
                ],
                details: { framework: params.framework },
            };
        },
    });
    pi.registerTool({
        name: "osint",
        label: "OSINT Investigation",
        description: "Run an OSINT investigation. Performs DNS, WHOIS, certificate transparency, " +
            "Wayback Machine, web tech fingerprinting, and platform searches.",
        promptSnippet: "OSINT investigation on a target",
        promptGuidelines: [
            "Use osint for reconnaissance on domains, IPs, usernames, emails, or URLs.",
            "Target type is auto-detected if not specified.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            target: Type.String({
                description: "Target: domain, IP, username, email, or URL",
            }),
            type: Type.Optional(Type.String({
                description: "Investigation type: domain, ip, username, email, url (auto-detected)",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            return {
                content: [
                    { type: "text", text: await callHandler("handleOsint", params) },
                ],
                details: { target: params.target },
            };
        },
    });
    pi.registerTool({
        name: "memory",
        label: "Security Memory",
        description: "Cross-session security memory powered by SQLite FTS5. Search for previous " +
            "findings, techniques, IOCs, and engagement notes.",
        promptSnippet: "Cross-session security memory (search/store/stats)",
        promptGuidelines: [
            "Use memory search when the user references past engagements, findings, or techniques.",
            "Use memory store to persist important findings, IOCs, or technique results.",
            "Use memory stats for an overview of stored knowledge.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            action: Type.String({ description: "search, store, or stats" }),
            query: Type.Optional(Type.String({ description: "Search query (for action=search)" })),
            content: Type.Optional(Type.String({ description: "Content to store (for action=store)" })),
            tags: Type.Optional(Type.String({
                description: "Comma-separated tags (for action=store)",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const handlerMap = {
                store: "handleStore",
                stats: "handleStats",
                search: "handleSearch",
            };
            const handler = handlerMap[params.action] || "handleSearch";
            return {
                content: [
                    { type: "text", text: await callHandler(handler, params) },
                ],
                details: { action: params.action },
            };
        },
    });
    pi.registerTool({
        name: "benchmark",
        label: "CTF Benchmark",
        description: "Run CTF benchmark suites to measure security agent capability. " +
            "Supports NYU CTF (205), PicoCTF (56), OverTheWire (93).",
        promptSnippet: "Run CTF benchmark suites",
        promptGuidelines: [
            "Use benchmark to run, check status, or view results of CTF benchmark suites.",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            action: Type.Optional(Type.String({ description: "status (default), run, or results" })),
            suite: Type.Optional(Type.String({ description: "Suite: nyu-ctf, picoctf, overthewire" })),
            challenge: Type.Optional(Type.String({
                description: "Specific challenge name for single runs",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const args = { _: [params.action || "status"] };
            if (params.suite)
                args._.push("--suite", params.suite);
            if (params.challenge)
                args._.push("--challenge", params.challenge);
            return {
                content: [
                    { type: "text", text: await callHandler("handleBenchmark", args) },
                ],
                details: { action: params.action || "status" },
            };
        },
    });
    pi.registerTool({
        name: "lookup",
        label: "Knowledge Lookup",
        description: "Query NERF's security knowledge base. Returns ranked chunks from 195 " +
            "knowledge docs and 1,539 skill domain summaries via FTS5 full-text search.",
        promptSnippet: "Search NERF security knowledge base",
        promptGuidelines: [
            "Use lookup when the model needs security domain knowledge mid-conversation.",
            "Pass domain to filter results to a specific security domain.",
            "Pass mode to boost results matching the active NERF mode (red, blue, privacy, etc.).",
        ],
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            query: Type.String({
                description: "Search query — security topic, technique, or vulnerability",
            }),
            domain: Type.Optional(Type.String({
                description: "Filter to domain: application-security, network-security, cloud-security, etc.",
            })),
            mode: Type.Optional(Type.String({
                description: "Boost results for mode: red, blue, purple, privacy, recon, incident, architect",
            })),
            limit: Type.Optional(Type.Number({ description: "Max results (default: 10)", default: 10 })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            try {
                const store = await knowledgeStore();
                if (!store) {
                    return {
                        content: [
                            {
                                type: "text",
                                text: JSON.stringify({
                                    results: [],
                                    message: "Knowledge index not available. Run: nerf index --rebuild",
                                }),
                            },
                        ],
                        details: { status: "no-index" },
                    };
                }
                const results = store.search(params.query, {
                    mode: params.mode,
                    domain: params.domain,
                    limit: params.limit || 10,
                });
                const formatted = results.map((r) => ({
                    source_file: r.source_file,
                    section_heading: r.section_heading,
                    content: (r.content || "").substring(0, 500),
                    domain: r.domain,
                    rank: r.adjusted_rank ?? r.rank,
                }));
                return {
                    content: [
                        {
                            type: "text",
                            text: JSON.stringify({
                                results: formatted,
                                count: formatted.length,
                            }),
                        },
                    ],
                    details: { query: params.query, count: formatted.length },
                };
            }
            catch (e) {
                const msg = e instanceof Error ? e.message : String(e);
                return {
                    content: [
                        {
                            type: "text",
                            text: JSON.stringify({
                                results: [],
                                message: "Knowledge index not available. Run: nerf index --rebuild",
                                error: msg,
                            }),
                        },
                    ],
                    details: { status: "error", error: msg },
                };
            }
        },
    });
    // ── Recon tools (lightweight, no external binaries) ──
    pi.registerTool({
        name: "techdetect",
        label: "Technology Detection",
        description: "Fingerprint a web target's technology stack via HTTP response analysis. " +
            "Detects frameworks, servers, languages, and security headers. Pure HTTP.",
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            url: Type.String({
                description: "Target URL to fingerprint (e.g., http://localhost:8080)",
            }),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const r = await recon();
            if (!r)
                return {
                    content: [{ type: "text", text: "Recon tools not available" }], details: {},
                };
            const result = await r.techdetect({ url: params.url });
            return {
                content: [
                    { type: "text", text: JSON.stringify(result, null, 2) },
                ],
                details: { detections: result.detections?.length || 0 },
            };
        },
    });
    pi.registerTool({
        name: "decode",
        label: "Multi-Format Decoder",
        description: "Decode data through multiple encoding layers. Supports base64, hex, URL encoding, " +
            "and JWT token decoding. Auto-detects encoding when not specified.",
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            data: Type.String({ description: "Data to decode" }),
            encoding: Type.Optional(Type.String({
                description: "Encoding hint: 'base64', 'hex', 'url', 'jwt', or 'auto' (default: auto)",
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const r = await recon();
            if (!r)
                return {
                    content: [{ type: "text", text: "Recon tools not available" }], details: {},
                };
            const result = r.decode({ data: params.data, encoding: params.encoding });
            return {
                content: [
                    { type: "text", text: JSON.stringify(result, null, 2) },
                ],
                details: { results: result.results?.length || 0 },
            };
        },
    });
    pi.registerTool({
        name: "dirprobe",
        label: "Directory Probe",
        description: "Probe common web paths on a target URL to discover hidden endpoints, admin panels, " +
            "API docs, backup files, and sensitive resources.",
        // @ts-ignore TypeBox version mismatch between extension and pi-coding-agent
        parameters: Type.Object({
            url: Type.String({
                description: "Base URL to probe (e.g., http://localhost:8080)",
            }),
            paths: Type.Optional(Type.Array(Type.String(), {
                description: "Custom paths to probe (overrides default wordlist)",
            })),
            concurrency: Type.Optional(Type.Number({
                description: "Parallel requests (default: 10)",
                default: 10,
            })),
        }),
        async execute(_id, params, _signal, _onUpdate, _ctx) {
            const r = await recon();
            if (!r)
                return {
                    content: [{ type: "text", text: "Recon tools not available" }], details: {},
                };
            const result = await r.dirprobe({
                url: params.url,
                paths: params.paths,
                concurrency: params.concurrency,
            });
            return {
                content: [
                    { type: "text", text: JSON.stringify(result, null, 2) },
                ],
                details: {
                    found: result.found?.length || 0,
                    probed: result.probed || 0,
                },
            };
        },
    });
}
