import { describe, expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createFrameworkMcpServer } from "../src/index.ts";

function fixture() {
  const root = mkdtempSync(join(tmpdir(), "wrnexus-mcp-"));
  for (const dir of ["app/pages", "app/api", "app/components", "app/db/migrations", "docs"])
    mkdirSync(join(root, dir), { recursive: true });
  writeFileSync(join(root, "app/pages/index.wrn"), "<h1>Home</h1>");
  writeFileSync(join(root, "app/api/users.ts"), "export const GET = () => Response.json([])");
  writeFileSync(
    join(root, "app/components/Button.wrn"),
    "prop label: string\nevent click\n<button>{label}</button>",
  );
  writeFileSync(join(root, "app/db/migrations/001.sql"), "CREATE TABLE users(id TEXT);");
  writeFileSync(join(root, "docs/GUIDE.md"), "# Guide");
  writeFileSync(
    join(root, "package.json"),
    JSON.stringify({ dependencies: { "@wrnexus/core": "0.8.0", other: "1.0.0" } }),
  );
  return root;
}

describe("WRNexus MCP", () => {
  test("exposes application framework context through bounded tools", async () => {
    const server = createFrameworkMcpServer(fixture(), {
      fetch: (async (input: URL | RequestInfo) =>
        new Response(null, {
          status: String(input).endsWith("readyz") ? 503 : 200,
        })) as unknown as typeof fetch,
      runtimeErrors: () => [{ message: "bad", token: "secret" }],
    });
    expect(((await server.call("wrnexus_routes")) as any[]).map((route) => route.path)).toEqual([
      "/",
      "/users",
    ]);
    expect(await server.call("wrnexus_components")).toEqual([
      { name: "Button", file: "app/components/Button.wrn", props: ["label"], events: ["click"] },
    ]);
    expect(((await server.call("wrnexus_database_schema")) as any[])[0].content).toContain(
      "CREATE TABLE",
    );
    expect(await server.call("wrnexus_packages")).toEqual([
      { name: "@wrnexus/core", version: "0.8.0" },
    ]);
    expect(await server.call("wrnexus_runtime_errors")).toEqual([
      { message: "bad", token: "[REDACTED]" },
    ]);
    expect(await server.call("wrnexus_dev_status")).toMatchObject({
      liveness: { ok: true },
      readiness: { ok: false },
    });
  });
  test("speaks MCP JSON-RPC initialize, list and call", async () => {
    const server = createFrameworkMcpServer(fixture());
    expect(await server.handle({ jsonrpc: "2.0", id: 1, method: "initialize" })).toHaveProperty(
      "result.serverInfo.name",
      "wrnexus",
    );
    expect(await server.handle({ jsonrpc: "2.0", id: 2, method: "tools/list" })).toHaveProperty(
      "result.tools.0.name",
      "wrnexus_routes",
    );
    const result = await server.handle({
      jsonrpc: "2.0",
      id: 3,
      method: "tools/call",
      params: { name: "wrnexus_docs", arguments: {} },
    });
    expect(result).toHaveProperty("result.structuredContent.value.0", "docs/GUIDE.md");
  });
  test("rejects documentation traversal", async () => {
    const server = createFrameworkMcpServer(fixture());
    await expect(server.call("wrnexus_docs", { file: "../secret" })).rejects.toThrow(
      "WRN-MCP-DOC-PATH",
    );
  });
});
