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

/**
 * build.js: BUILD mode agent for NERF execution engine.
 *
 * Handles security tooling, automation scripts, CI/CD pipeline security,
 * and infrastructure-as-code. Can layer with other modes (RED+BUILD, BLUE+BUILD).
 *
 * All tool execution is routed through ToolSandbox for:
 *   - Path validation (jail to project root, sensitive path blocking)
 *   - Command allowlisting (only permitted build/dev commands)
 *   - Optional Docker sandboxing (when available)
 *
 * @module execution-engine/modes/build
 */

import { ModeAgentConfig, ToolRegistry, NullValidator } from '../framework.js';

const debug = process.env.NERF_DEBUG === '1'
  ? (/** @type {string} */ msg) => process.stderr.write(`[build-mode] ${msg}\n`)
  : () => {};

/**
 * Build mode system prompt.
 */
const BUILD_SYSTEM_PROMPT = `You are NERF in BUILD mode: a security tooling and automation engineer.

You write production-grade security tools, automation scripts, CI/CD pipeline security,
and infrastructure-as-code. All code follows these standards:

- Node.js 22+ with ESM modules. TypeScript preferred, JavaScript acceptable.
- Python 3.12+ for security tooling, automation, and analysis scripts.
- Error handling required. No bare catches. No swallowed exceptions.
- Comment non-obvious logic. Self-documenting naming for the rest.
- Security-first defaults. Input validation, output encoding, least privilege, fail-safe.
- No direct LLM SDK imports. All LLM calls route through pi-mono.

Sub-skill routing:
- secure-coding/: OWASP prevention, input validation, auth patterns, secure defaults
- devsecops/: SAST/DAST/SCA, CI/CD security, SBOM, SLSA, container scanning
- automation-scripting/: Ansible hardening, Terraform IaC, Docker Compose, security scripts
- supply-chain-security/: Dependency management, SBOM lifecycle, typosquatting, artifact verification
- security-operations-automation/: SOAR playbooks, ChatOps, threat intel workflows
- nuclei-templating/: Custom vulnerability checks, CVE detection templates
- pr-security-review/: Code review for vulnerabilities, diff analysis, security regression

## Security Constraints
- File operations are jailed to the project root directory
- Only build/dev commands are permitted (npm, node, python, git, make, etc.)
- Sensitive paths (.ssh, .env, credentials) are blocked from write access
- All tool inputs are validated before execution

Every output includes:
- DETECTION OPPORTUNITIES where applicable
- Privacy implications for any data handling
`;

/**
 * Build mode tools — all routed through ToolSandbox.
 *
 * @param {import('../tool-sandbox.js').ToolSandbox} sandbox
 * @returns {ToolRegistry}
 */
function makeBuildTools(sandbox) {
  const tools = new ToolRegistry();

  tools.register('write_code', {
    name: 'write_code',
    description: 'Write or modify code files with security-first defaults. ' +
      'Files must be within the project directory.',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string', description: 'File path to write (relative to project root)' },
        content: { type: 'string', description: 'File content' },
        language: { type: 'string', description: 'Programming language' },
      },
      required: ['path', 'content'],
    },
  }, async (_ctx, { path, content }) => {
    return sandbox.writeFile(path, content);
  });

  tools.register('run_command', {
    name: 'run_command',
    description: 'Execute a shell command for building, testing, or verifying. ' +
      'Only build/dev commands are permitted (npm, node, python, git, make, etc.).',
    input_schema: {
      type: 'object',
      properties: {
        command: { type: 'string', description: 'Shell command to execute' },
        cwd: { type: 'string', description: 'Working directory (relative to project root)' },
      },
      required: ['command'],
    },
  }, async (_ctx, { command, cwd }) => {
    return sandbox.execCommand(command, cwd);
  });

  tools.register('read_file', {
    name: 'read_file',
    description: 'Read a file to understand existing code before modifying. ' +
      'Files must be within the project directory.',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string', description: 'File path to read (relative to project root)' },
      },
      required: ['path'],
    },
  }, async (_ctx, { path }) => {
    return sandbox.readFile(path);
  });

  return tools;
}

/**
 * Register BUILD mode with the execution engine.
 * @param {Function} registerMode
 */
export function register(registerMode) {
  registerMode('BUILD', (context) => {
    // Lazy-create a ToolSandbox on first use. The sandbox is initialized
    // once and reused across all tool calls within this agent session.
    let _sandbox = null;

    const getSandbox = async () => {
      if (!_sandbox) {
        const { ToolSandbox } = await import('../tool-sandbox.js');
        const projectRoot = context?.projectRoot || process.cwd();
        const useDocker = context?.useDocker ?? (process.env.NERF_BUILD_DOCKER === '1');
        _sandbox = new ToolSandbox({
          projectRoot,
          useDocker,
          dockerImage: context?.dockerImage || 'node:22-slim',
          allowNetwork: true,
        });
        await _sandbox.init();
        debug(`BUILD mode sandbox initialized (docker=${_sandbox.isDockerMode}, root=${projectRoot})`);
      }
      return _sandbox;
    };

    // Pre-initialize sandbox eagerly so tools can use it synchronously
    // within the ToolRegistry dispatch (which doesn't await).
    // We use a proxy tools registry that initializes on first dispatch.
    const tools = new ToolRegistry();

    tools.register('write_code', {
      name: 'write_code',
      description: 'Write or modify code files with security-first defaults. ' +
        'Files must be within the project directory.',
      input_schema: {
        type: 'object',
        properties: {
          path: { type: 'string', description: 'File path to write (relative to project root)' },
          content: { type: 'string', description: 'File content' },
          language: { type: 'string', description: 'Programming language' },
        },
        required: ['path', 'content'],
      },
    }, async (_ctx, { path, content }) => {
      const sandbox = await getSandbox();
      return sandbox.writeFile(path, content);
    });

    tools.register('run_command', {
      name: 'run_command',
      description: 'Execute a shell command for building, testing, or verifying. ' +
        'Only build/dev commands are permitted (npm, node, python, git, make, etc.).',
      input_schema: {
        type: 'object',
        properties: {
          command: { type: 'string', description: 'Shell command to execute' },
          cwd: { type: 'string', description: 'Working directory (relative to project root)' },
        },
        required: ['command'],
      },
    }, async (_ctx, { command, cwd }) => {
      const sandbox = await getSandbox();
      return sandbox.execCommand(command, cwd);
    });

    tools.register('read_file', {
      name: 'read_file',
      description: 'Read a file to understand existing code before modifying. ' +
        'Files must be within the project directory.',
      input_schema: {
        type: 'object',
        properties: {
          path: { type: 'string', description: 'File path to read (relative to project root)' },
        },
        required: ['path'],
      },
    }, async (_ctx, { path }) => {
      const sandbox = await getSandbox();
      return sandbox.readFile(path);
    });

    return new ModeAgentConfig({
      mode: 'BUILD',
      systemPromptTemplate: BUILD_SYSTEM_PROMPT,
      toolRegistry: tools,
      validator: new NullValidator(),
      maxIterations: context?.maxIterations || 15,
    });
  });
}
