import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { createSkillManagerTool } from "../../.opencode/tools/skill_manager.js";
import { type RuntimeSessionContext } from "../../src/runtime/sessionContext.js";
import { SkillStore } from "../../src/skills/store.js";

describe("skill_manager tool", () => {
  let tempDir: string;
  let skillStore: SkillStore;
  let context: RuntimeSessionContext;

  const toolContext = {
    abort: new AbortController().signal,
    agent: "test",
    ask: (() => undefined) as never,
    directory: "",
    messageID: "message-1",
    metadata: () => undefined,
    sessionID: "session-1",
    worktree: "",
  };

  const skillDocument = (body: string) =>
    [
      "---",
      "name: pressure-review",
      "description: Pressure review workflow.",
      "---",
      "",
      body,
    ].join("\n");

  beforeEach(async () => {
    tempDir = await mkdtemp(join(tmpdir(), "tjwater-skill-tool-"));
    skillStore = new SkillStore(
      join(tempDir, "skills"),
      join(tempDir, "backup", "skills"),
    );
    context = {
      actorKey: "actor-1",
      allowLearningWrite: true,
      clientSessionId: "client-session-1",
      projectKey: "project-1",
      sessionId: "session-1",
      traceId: "trace-1",
    };
  });

  afterEach(async () => {
    await rm(tempDir, { force: true, recursive: true });
  });

  it("dispatches skill-level write, overwrite, and remove actions", async () => {
    const tool = createSkillManagerTool(
      skillStore,
      { read: () => context },
      Promise.resolve(),
    );

    const writeResult = JSON.parse(
      await tool.execute(
        {
          action: "write_skill",
          content: skillDocument("# Pressure Review"),
          reason: "verified reusable workflow",
          skill_path: "workflow/pressure-review",
        },
        toolContext,
      ) as string,
    );
    expect(writeResult.decision).toBe("accepted");
    await expect(readFile(writeResult.target, "utf8")).resolves.toContain(
      "# Pressure Review\n",
    );

    const updateResult = JSON.parse(
      await tool.execute(
        {
          action: "write_skill",
          content: skillDocument("# Updated Pressure Review"),
          reason: "verified reusable workflow overwrite",
          skill_path: "workflow/pressure-review",
        },
        toolContext,
      ) as string,
    );
    expect(updateResult.decision).toBe("accepted");
    await expect(readFile(updateResult.target, "utf8")).resolves.toContain(
      "# Updated Pressure Review\n",
    );

    const removeResult = JSON.parse(
      await tool.execute(
        {
          action: "remove_skill",
          reason: "workflow is obsolete",
          skill_path: "workflow/pressure-review",
        },
        toolContext,
      ) as string,
    );
    expect(removeResult.decision).toBe("accepted");
    await expect(readFile(removeResult.target, "utf8")).rejects.toThrow();
  });

  it("writes the root skills index through the reserved alias", async () => {
    const tool = createSkillManagerTool(
      skillStore,
      { read: () => context },
      Promise.resolve(),
    );

    const writeResult = JSON.parse(
      await tool.execute(
        {
          action: "write_skill",
          content: [
            "---",
            "name: skills",
            "description: TJWater Skills root index.",
            "---",
            "",
            "# TJWater Skills",
          ].join("\n"),
          reason: "refresh root skills index",
          skill_path: "__root__",
        },
        toolContext,
      ) as string,
    );

    expect(writeResult.decision).toBe("accepted");
    await expect(readFile(writeResult.target, "utf8")).resolves.toContain(
      "# TJWater Skills\n",
    );
  });
});
