/**
 * PR-3: Search Shadow Migration Test
 * 
 * Run: node --test test/memory-core/search-shadow.test.mjs
 * 
 * Tests the shadow comparison tool:
 *   1. Shadow tool is runnable
 *   2. All 22 queries complete
 *   3. Shape compatibility reported for each
 *   4. Empty query handled gracefully
 *   5. Production check still passes
 */

import { describe, it, before } from "node:test";
import assert from "node:assert";
import { join, resolve } from "node:path";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";

const __dirname = join(fileURLToPath(import.meta.url), "..", "..", "..");
const ROOT = resolve(__dirname);
const SHADOW_TOOL = join(ROOT, "scripts", "memory-search-shadow.mjs");

describe("PR-3: Search Shadow Migration Test", () => {
  
  let shadowResult;

  before(async () => {
    // Run shadow tool with --json for structured output
    const result = spawnSync("node", [SHADOW_TOOL, "--json"], {
      cwd: ROOT,
      encoding: "utf8",
      timeout: 60000,
      maxBuffer: 2 * 1024 * 1024,
    });

    const output = result.stdout + result.stderr;
    
    // Extract JSON from output (may have other text)
    const jsonMatch = output.match(/\{[\s\S]*"results"[\s\S]*\}/);
    if (jsonMatch) {
      try {
        shadowResult = JSON.parse(jsonMatch[0]);
      } catch {
        // Fall back to running without --json and parsing text
        shadowResult = null;
      }
    }
    
    console.log(output.slice(-500));
  });

  // ─── Test 1 ──────────────────────────────────────────
  it("shadow tool is runnable and produces results", () => {
    assert.ok(shadowResult, "Shadow tool should produce JSON output");
    assert.ok(typeof shadowResult.totalQueries === "number", "Should have totalQueries");
    assert.ok(shadowResult.totalQueries >= 20, `Expected >=20 queries, got ${shadowResult.totalQueries}`);
  });

  // ─── Test 2 ──────────────────────────────────────────
  it("all queries complete without crash", () => {
    assert.ok(Array.isArray(shadowResult.results), "results should be array");
    assert.equal(shadowResult.results.length, shadowResult.totalQueries,
      "Results count should match total queries");
  });

  // ─── Test 3 ──────────────────────────────────────────
  it("each query reports shapeCompatible", () => {
    for (const r of shadowResult.results) {
      assert.ok(typeof r.shapeCompatible === "boolean",
        `shapeCompatible should be boolean for query "${r.query}"`);
    }
  });

  // ─── Test 4 ──────────────────────────────────────────
  it("empty query handled gracefully (documented as known difference)", () => {
    const emptyResult = shadowResult.results.find(r => r.query === "");
    assert.ok(emptyResult, "Should have empty query test case");
    
    // Empty query: legacy FTS5 returns all, facade rejects
    // This is a KNOWN difference — facade is more correct
    assert.equal(emptyResult.legacyOk, true,
      "Legacy treats empty as match-all (known quirk)");
    assert.equal(emptyResult.facadeOk, false,
      "Facade rejects empty query (correct behavior)");
    // shapeCompatible may be false here — that's OK, documented
  });

  // ─── Test 5 ──────────────────────────────────────────
  it("high shape compatibility rate (>90%)", () => {
    const rate = shadowResult.passed / shadowResult.totalQueries;
    assert.ok(rate >= 0.9,
      `Shape compatibility rate ${Math.round(rate*100)}% below 90% threshold`);
  });

  // ─── Test 6 ──────────────────────────────────────────
  it("results have required fields", () => {
    const requiredFields = [
      "query", "legacyOk", "facadeOk", "legacyCount", "facadeCount",
      "topOverlap", "shapeCompatible", "latencyLegacyMs", "latencyFacadeMs",
    ];
    
    for (const r of shadowResult.results) {
      for (const field of requiredFields) {
        assert.ok(field in r, `Missing field "${field}" in result for "${r.query}"`);
      }
    }
  });

  // ─── Test 7 ──────────────────────────────────────────
  it("production check still passes after shadow", { timeout: 180000 }, () => {
    const result = spawnSync("bash", [join(ROOT, "scripts", "production-check.sh")], {
      cwd: ROOT,
      encoding: "utf8",
      timeout: 170000,
      maxBuffer: 2 * 1024 * 1024,
    });
    
    const output = result.stdout + result.stderr;
    
    assert.equal(result.status, 0,
      `Production check failed (exit ${result.status})`);
    assert.ok(output.includes("PRODUCTION CHECK PASSED"),
      "Production check should report PASSED");
  });

  // ─── Test 8 ──────────────────────────────────────────
  it("shadow compare does not modify any memory", async () => {
    const { readFileSync } = await import("node:fs");
    const memContent = readFileSync(join(ROOT, "MEMORY.md"), "utf8");
    
    // Re-run shadow tool
    spawnSync("node", [SHADOW_TOOL], {
      cwd: ROOT,
      encoding: "utf8",
      timeout: 60000,
    });

    // Verify MEMORY.md unchanged
    const memAfter = readFileSync(join(ROOT, "MEMORY.md"), "utf8");
    assert.equal(memAfter, memContent, "MEMORY.md must not be modified by shadow");
  });
});
