/**
 * GAIA Agent Contrastive Wrapper — iter 49.5
 *
 * Thin wrapper around runGaiaAgent that adds three ruflo intelligence hooks:
 *   1. PRE: memory_search_unified for relevant patterns
 *   2. DURING: trajectory recording (start/step/end) via memory store
 *   3. POST: memory_store of question+answer+verdict for future recall
 *
 * Purpose: measure whether ruflo's AgentDB intelligence (5,930 entries,
 * 26,490 patterns) provides a measurable lift on GAIA L1 when injected
 * as system context before the agent loop.
 *
 * Design constraints:
 *   - Does NOT change the underlying agent loop logic
 *   - Does NOT enable ADR-135 tracks (critic, decomposition, voting, MoE, KG)
 *   - Pure addition: memory before, trajectory during, store after
 *   - Graceful fallback: any hook failure is logged but does NOT fail the question
 *
 * Refs: ADR-133, iter 49.5, #2156
 */

import { execSync } from 'node:child_process';
import type { GaiaQuestion } from './gaia-loader.js';
import { runGaiaAgent, type GaiaAgentOptions, type GaiaAgentResult } from './gaia-agent.js';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface ContrastiveStats {
  memorySearchCalls: number;
  memorySearchHits: number;  // returned >= 1 result
  memoryStoreCount: number;
  trajectoryCount: number;
  totalPatternsInjected: number;
}

export interface ContrastiveAgentResult extends GaiaAgentResult {
  /** Number of memory patterns injected as context for this question. */
  patternsInjected?: number;
  /** Whether a trajectory was recorded for this question. */
  trajectoryRecorded?: boolean;
  /** Whether the question+answer was stored in memory after completion. */
  memoryStored?: boolean;
}

// ---------------------------------------------------------------------------
// Ruflo CLI helpers (best-effort — never throw)
// ---------------------------------------------------------------------------

const CLI_TIMEOUT_MS = 10_000;
const GAIA_NAMESPACE = 'gaia-l1-questions';

/**
 * Run memory search via CLI and return up to `limit` result summaries.
 * Returns empty array on any error (graceful fallback).
 */
function memorySearch(query: string, limit: number): string[] {
  try {
    const raw = execSync(
      `npx @claude-flow/cli@latest memory search --query ${JSON.stringify(query)} --limit ${limit}`,
      { encoding: 'utf-8', timeout: CLI_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'] },
    );
    // Parse table rows: extract Preview column (5th column in pipe-separated table)
    const rows = raw
      .split('\n')
      .filter((line) => line.startsWith('|') && !line.includes('Key') && !line.includes('---'))
      .map((line) => {
        const cols = line.split('|').map((c) => c.trim()).filter(Boolean);
        // cols: [Key, Score, Namespace, Preview]
        return cols[3] ?? '';
      })
      .filter((preview) => preview.length > 0 && !preview.includes('Preview'));
    return rows.slice(0, limit);
  } catch {
    return [];
  }
}

/**
 * Store a key/value in memory under the gaia namespace.
 * Best-effort — swallows errors.
 */
function memoryStore(key: string, value: object): boolean {
  try {
    const valueStr = JSON.stringify(value);
    execSync(
      `npx @claude-flow/cli@latest memory store --key ${JSON.stringify(key)} --value ${JSON.stringify(valueStr)} --namespace ${GAIA_NAMESPACE}`,
      { encoding: 'utf-8', timeout: CLI_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'] },
    );
    return true;
  } catch {
    return false;
  }
}

/**
 * Record a trajectory event (start/step/end) via memory store.
 * This is a lightweight proxy — the MCP trajectory tools are not available
 * from inside the benchmark harness. We persist the trajectory as memory
 * entries so they can be recalled later.
 */
function trajectoryRecord(type: 'start' | 'end', data: object): void {
  try {
    const key = `traj-gaia-l1-${type}-${Date.now()}`;
    execSync(
      `npx @claude-flow/cli@latest memory store --key ${JSON.stringify(key)} --value ${JSON.stringify(JSON.stringify(data))} --namespace trajectories`,
      { encoding: 'utf-8', timeout: CLI_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'] },
    );
  } catch {
    // Best-effort — trajectory recording never blocks progress
  }
}

// ---------------------------------------------------------------------------
// System prompt injection
// ---------------------------------------------------------------------------

/**
 * Build a context prefix to prepend to the system prompt when patterns
 * are found in memory. Returns empty string when patterns is empty.
 */
function buildMemoryContextPrefix(patterns: string[]): string {
  if (patterns.length === 0) return '';
  return (
    'Relevant patterns from prior ruflo work:\n' +
    patterns.map((p) => `- ${p.slice(0, 120)}`).join('\n') +
    '\n\n'
  );
}

// ---------------------------------------------------------------------------
// Contrastive wrapper
// ---------------------------------------------------------------------------

/**
 * Wrap runGaiaAgent with ruflo intelligence hooks.
 *
 * Hook points:
 *   1. memory_search before the agent loop (context injection)
 *   2. trajectory-start/end records via memory store
 *   3. memory_store after the final answer
 *
 * The underlying agent loop is called unchanged.
 */
export async function runGaiaAgentContrastive(
  question: GaiaQuestion,
  options: GaiaAgentOptions,
  stats: ContrastiveStats,
): Promise<ContrastiveAgentResult> {
  const questionId = question.task_id;

  // ---- 1. PRE: memory_search for relevant patterns ----------------------
  stats.memorySearchCalls++;
  const patterns = memorySearch(question.question, 3);
  const patternsInjected = patterns.length;
  if (patterns.length > 0) {
    stats.memorySearchHits++;
    stats.totalPatternsInjected += patterns.length;
  }

  // ---- 2. TRAJECTORY: start recording -----------------------------------
  trajectoryRecord('start', {
    task: 'gaia-l1',
    question_id: questionId,
    question_snippet: question.question.slice(0, 80),
    startedAt: new Date().toISOString(),
    patternsInjected,
  });

  // ---- Build patched options with memory context injected ---------------
  // We inject context by wrapping the question text (system prompt cannot be
  // overridden via GaiaAgentOptions today; instead we prepend context to
  // the question text as a user-visible hint). This is intentionally minimal.
  const contextPrefix = buildMemoryContextPrefix(patterns);
  const patchedQuestion: GaiaQuestion = contextPrefix
    ? { ...question, question: contextPrefix + question.question }
    : question;

  // ---- Run the actual agent loop (unchanged) ----------------------------
  const result = await runGaiaAgent(patchedQuestion, options);

  // ---- 3. POST: store question+answer+verdict ---------------------------
  const questionKey = `gaia-l1-q${questionId}-${Date.now()}`;
  const stored = memoryStore(questionKey, {
    question: question.question,
    answer: result.finalAnswer,
    questionId,
    model: options.model ?? 'claude-sonnet-4-6',
    turns: result.turns,
    timedOut: result.timedOut ?? false,
    storedAt: new Date().toISOString(),
  });
  if (stored) stats.memoryStoreCount++;

  // ---- TRAJECTORY: end recording ----------------------------------------
  trajectoryRecord('end', {
    task: 'gaia-l1',
    question_id: questionId,
    answer: result.finalAnswer,
    turns: result.turns,
    timedOut: result.timedOut ?? false,
    endedAt: new Date().toISOString(),
  });
  stats.trajectoryCount++;

  return {
    ...result,
    patternsInjected,
    trajectoryRecorded: true,
    memoryStored: stored,
  };
}

/**
 * Create a fresh ContrastiveStats counter object.
 */
export function createContrastiveStats(): ContrastiveStats {
  return {
    memorySearchCalls: 0,
    memorySearchHits: 0,
    memoryStoreCount: 0,
    trajectoryCount: 0,
    totalPatternsInjected: 0,
  };
}
