import { describe, expect, it } from "vitest";

import {
  clampHighlight,
  filterCommands,
  globalCommands,
  moveHighlight,
  projectCommands,
} from "./palette";

describe("projectCommands", () => {
  it("includes nav + action commands wired to the project id", () => {
    const cmds = projectCommands("p1");
    const write = cmds.find((c) => c.id === "nav-write");
    expect(write?.href).toBe("/projects/p1/write");
    const genChar = cmds.find((c) => c.id === "action-gen-character");
    expect(genChar?.kind).toBe("action");
    expect(genChar?.href).toBe("/projects/p1/codex?gen=character");
  });

  it("always offers a 工具箱 nav command", () => {
    const toolbox = projectCommands("p1").find((c) => c.id === "nav-toolbox");
    expect(toolbox?.kind).toBe("navigate");
    expect(toolbox?.href).toBe("/projects/p1/toolbox");
  });

  it("generates one action-gen-<key> per toolbox tool deep-linking with ?open", () => {
    const cmds = projectCommands("p1", [
      { key: "brainstorm", title: "脑洞生成器", genre: "玄幻" },
      { key: "book-title", title: "书名生成器" },
    ]);
    const brainstorm = cmds.find((c) => c.id === "action-gen-brainstorm");
    expect(brainstorm?.kind).toBe("action");
    expect(brainstorm?.href).toBe("/projects/p1/toolbox?open=brainstorm");
    expect(brainstorm?.title).toBe("脑洞生成器");
    expect(brainstorm?.keywords).toContain("玄幻");
    expect(cmds.find((c) => c.id === "action-gen-book-title")?.href).toBe(
      "/projects/p1/toolbox?open=book-title",
    );
  });

  it("emits no tool commands when none provided", () => {
    const ids = projectCommands("p1").map((c) => c.id);
    expect(ids.some((id) => id === "action-gen-brainstorm")).toBe(false);
  });
});

describe("globalCommands", () => {
  it("offers home + settings", () => {
    expect(globalCommands().map((c) => c.id)).toEqual([
      "nav-home",
      "nav-settings",
    ]);
  });
});

describe("filterCommands", () => {
  const cmds = projectCommands("p1");

  it("returns all on empty query", () => {
    expect(filterCommands(cmds, "  ")).toHaveLength(cmds.length);
  });

  it("matches on title", () => {
    const out = filterCommands(cmds, "审稿");
    expect(out.map((c) => c.id)).toContain("nav-review");
  });

  it("matches on keyword case-insensitively", () => {
    const out = filterCommands(cmds, "FORESHADOW");
    expect(out.map((c) => c.id)).toContain("nav-foreshadow");
  });

  it("matches generation actions by 角色/世界观", () => {
    expect(filterCommands(cmds, "角色").map((c) => c.id)).toContain(
      "action-gen-character",
    );
    expect(filterCommands(cmds, "世界观").map((c) => c.id)).toContain(
      "action-gen-world",
    );
  });

  it("returns empty when nothing matches", () => {
    expect(filterCommands(cmds, "zzzz-no-match")).toEqual([]);
  });
});

describe("clampHighlight / moveHighlight", () => {
  it("wraps within [0, len)", () => {
    expect(clampHighlight(0, 3)).toBe(0);
    expect(clampHighlight(3, 3)).toBe(0);
    expect(clampHighlight(-1, 3)).toBe(2);
    expect(clampHighlight(5, 0)).toBe(0);
  });

  it("moves up/down with wrap", () => {
    expect(moveHighlight(0, 1, 3)).toBe(1);
    expect(moveHighlight(2, 1, 3)).toBe(0);
    expect(moveHighlight(0, -1, 3)).toBe(2);
  });
});
