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

const invoke = vi.fn();
const listen = vi.fn();
vi.mock("@tauri-apps/api/core", () => ({
  invoke: (...args: unknown[]) => invoke(...args),
}));
vi.mock("@tauri-apps/api/event", () => ({
  listen: (...args: unknown[]) => listen(...args),
}));

import { TauriFocusedProjectGateway } from "./focusedProject";

describe("TauriFocusedProjectGateway (#47)", () => {
  beforeEach(() => {
    invoke.mockReset().mockResolvedValue(null);
    listen.mockReset();
  });

  it("set/get relay to the backend focused-project commands", async () => {
    const gw = new TauriFocusedProjectGateway();

    await gw.setFocusedProject({ id: "p1", name: "alpha", root: "/p/a" });
    expect(invoke).toHaveBeenCalledWith("set_focused_project", {
      project: { id: "p1", name: "alpha", root: "/p/a" },
    });

    await gw.setFocusedProject(null);
    expect(invoke).toHaveBeenCalledWith("set_focused_project", {
      project: null,
    });

    invoke.mockResolvedValueOnce({ id: "p2", name: "beta", root: "/p/b" });
    await expect(gw.getFocusedProject()).resolves.toEqual({
      id: "p2",
      name: "beta",
      root: "/p/b",
    });
    expect(invoke).toHaveBeenCalledWith("get_focused_project");

    // A `null`/undefined focus normalises to `null`.
    invoke.mockResolvedValueOnce(null);
    await expect(gw.getFocusedProject()).resolves.toBeNull();
  });

  it("onFocusedProjectChanged listens on the channel and forwards the project (or null)", async () => {
    let raw: ((e: { payload: unknown }) => void) | undefined;
    const unlisten = vi.fn();
    listen.mockImplementation((_name: string, cb: typeof raw) => {
      raw = cb;
      return Promise.resolve(unlisten);
    });

    const gw = new TauriFocusedProjectGateway();
    const handler = vi.fn();
    const off = await gw.onFocusedProjectChanged(handler);

    expect(listen).toHaveBeenCalledWith(
      "focused-project://changed",
      expect.any(Function),
    );

    raw?.({ payload: { project: { id: "p1", name: "alpha", root: "/p/a" } } });
    expect(handler).toHaveBeenLastCalledWith({
      id: "p1",
      name: "alpha",
      root: "/p/a",
    });

    raw?.({ payload: { project: null } });
    expect(handler).toHaveBeenLastCalledWith(null);

    off();
    expect(unlisten).toHaveBeenCalled();
  });
});
