import assert from "node:assert/strict";
import { chmod, mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";

import hippoExtension from "../hippo-memory-pi/index.ts";

test("official Hippo extension registers five tools and runs lifecycle CLI calls", async () => {
  const root = await mkdtemp(join(tmpdir(), "my-pi-hippo-extension-"));
  const bin = join(root, "bin");
  const project = join(root, "project");
  const log = join(root, "hippo.log");
  await mkdir(bin, { recursive: true });
  await mkdir(join(project, ".hippo"), { recursive: true });
  const hippo = join(bin, "hippo");
  await writeFile(
    hippo,
    `#!/bin/sh\nprintf '%s\\n' "$*" >> "$HIPPO_TEST_LOG"\ncase "$1" in\n  status) printf '%s\\n' 'Hippo status ok' ;;\n  context) printf '%s\\n' 'Remembered project context for testing' ;;\n  recall) printf '%s\\n' 'Relevant project memory' ;;\n  remember) printf '%s\\n' 'Remembered [test]' ;;\n  outcome) printf '%s\\n' 'Outcome recorded' ;;\n  sleep) printf '%s\\n' 'Sleep complete' ;;\nesac\n`,
    "utf8",
  );
  await chmod(hippo, 0o755);

  const previousPath = process.env.PATH;
  const previousLog = process.env.HIPPO_TEST_LOG;
  process.env.PATH = `${bin}:${previousPath ?? ""}`;
  process.env.HIPPO_TEST_LOG = log;
  try {
    const handlers = new Map<string, Array<(event: any, ctx: any) => Promise<any>>>();
    const tools = new Map<string, any>();
    hippoExtension({
      on(name: string, handler: (event: any, ctx: any) => Promise<any>) {
        const entries = handlers.get(name) ?? [];
        entries.push(handler);
        handlers.set(name, entries);
      },
      registerTool(tool: any) {
        tools.set(tool.name, tool);
      },
    });

    assert.deepEqual(
      [...tools.keys()].sort(),
      ["hippo_context", "hippo_outcome", "hippo_recall", "hippo_remember", "hippo_status"],
    );
    const ctx = { cwd: project };
    const startResult = await handlers.get("session_start")?.[0]?.({}, ctx);
    assert.match(startResult.systemPromptAppend, /Remembered project context/);
    const rememberResult = await tools.get("hippo_remember").execute("call-1", { text: "A durable lesson" }, undefined, undefined, ctx);
    assert.match(rememberResult.content[0].text, /Remembered \[test\]/);
    await handlers.get("tool_result")?.[0]?.(
      { isError: true, toolName: "build", content: "Compilation failed because the generated symbol was missing" },
      ctx,
    );
    await handlers.get("session_shutdown")?.[0]?.({}, ctx);

    const calls = await readFile(log, "utf8");
    assert.match(calls, /context --auto/);
    assert.match(calls, /remember A durable lesson/);
    assert.match(calls, /remember Tool 'build' failed:/);
    assert.match(calls, /sleep/);
  } finally {
    process.env.PATH = previousPath;
    if (previousLog === undefined) delete process.env.HIPPO_TEST_LOG;
    else process.env.HIPPO_TEST_LOG = previousLog;
  }
});
