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

/**
 * Evaluator pipeline hook: registers after-scan and after-review hooks
 * that prepare (and optionally execute) QA evaluation of security findings.
 *
 * @module evaluator/hook
 */

import { HookEvent } from '../pipeline/hooks.js';
import { EvaluatorEngine } from './engine.js';

/**
 * Register the evaluator hook on AFTER_SCAN and AFTER_REVIEW events.
 *
 * In lazy mode (default), the hook prepares the evaluation prompt and stores
 * it in ctx.meta for later use. In eager mode (autoEvaluate + llmClient),
 * it also calls the LLM and parses verdicts inline.
 *
 * @param {import('../pipeline/hooks.js').PipelineHooks} pipelineHooks
 * @param {object} [options]
 * @param {boolean} [options.autoEvaluate=false] - If true and llmClient is provided, run evaluation inline
 * @param {object}  [options.llmClient]          - LLM client with a .complete(prompt) method
 * @param {number}  [options.maxFindings=25]     - Max findings per evaluation batch
 * @param {number}  [options.maxCharsPerFinding=2000] - Truncate threshold per finding
 */
export function registerEvaluatorHook(pipelineHooks, options = {}) {
  const {
    autoEvaluate = false,
    llmClient = null,
    maxFindings = 25,
    maxCharsPerFinding = 2000,
  } = options;

  const engine = new EvaluatorEngine({ maxFindings, maxCharsPerFinding });

  const hookFn = async (ctx) => {
    try {
      // Extract findings from the result
      const findings = ctx.result?.findings;
      if (!findings || !Array.isArray(findings) || findings.length === 0) {
        return; // Nothing to evaluate
      }

      // Build the evaluation prompt
      const { prompt, findingCount, rubricType } = engine.buildPrompt(findings);
      ctx.meta.evaluatorPrompt = prompt;
      ctx.meta.evaluatorFindingCount = findingCount;
      ctx.meta.evaluatorRubricType = rubricType;

      // If auto-evaluate is enabled and we have an LLM client, run evaluation
      if (autoEvaluate && llmClient) {
        const response = await llmClient.complete(prompt);
        const { verdicts, parseErrors } = engine.parseResponse(response);
        ctx.meta.evaluatorVerdicts = verdicts;
        if (parseErrors.length > 0) {
          ctx.meta.evaluatorParseErrors = parseErrors;
        }
      }
    } catch (err) {
      // Never abort the pipeline on evaluator errors
      ctx.meta.evaluatorError = err.message;
    }
  };

  hookFn._hookName = 'evaluator';
  hookFn._hookPriority = 900;

  pipelineHooks.hook(HookEvent.AFTER_SCAN, hookFn, { name: 'evaluator', priority: 900 });
  pipelineHooks.hook(HookEvent.AFTER_REVIEW, hookFn, { name: 'evaluator', priority: 900 });

  return pipelineHooks;
}
