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 { TauriWindowGateway } from "./window";

describe("TauriWindowGateway (#23)", () => {
  beforeEach(() => {
    invoke.mockReset().mockResolvedValue({});
    listen.mockReset();
  });

  it("open/close relay panel-only payloads to the backend commands (#47)", async () => {
    const gw = new TauriWindowGateway();
    await gw.openViewWindow("tickets");
    expect(invoke).toHaveBeenCalledWith("open_view_window", {
      panel: "tickets",
    });
    await gw.closeViewWindow("git");
    expect(invoke).toHaveBeenCalledWith("close_view_window", {
      panel: "git",
    });
  });

  it("opens plugin layout windows through the backend command", async () => {
    invoke.mockResolvedValueOnce({
      label: "view-plugin-layout",
      url: "index.html?pluginLayout=1",
      alreadyOpen: false,
      providerPluginDisplayName: "Plugin",
      layoutLabel: "Dashboard",
      surface: {
        pluginId: "dev.acme.plugin",
        layoutType: "dev.acme.plugin.dashboard",
        state: { tab: "overview" },
      },
    });
    const gw = new TauriWindowGateway();

    await expect(
      gw.openPluginLayoutWindow({
        pluginId: "dev.acme.plugin",
        layoutType: "dev.acme.plugin.dashboard",
        state: { tab: "overview" },
      }),
    ).resolves.toMatchObject({
      label: "view-plugin-layout",
      surface: { layoutType: "dev.acme.plugin.dashboard" },
    });

    expect(invoke).toHaveBeenCalledWith("open_plugin_layout_window", {
      input: {
        pluginId: "dev.acme.plugin",
        layoutType: "dev.acme.plugin.dashboard",
        state: { tab: "overview" },
      },
    });
  });

  it("onViewWindowClosed listens on the lifecycle channel and forwards only closes", async () => {
    // Capture the raw Tauri listener so we can drive lifecycle events at will.
    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 TauriWindowGateway();
    const handler = vi.fn();
    const off = await gw.onViewWindowClosed(handler);

    expect(listen).toHaveBeenCalledWith(
      "view-window://lifecycle",
      expect.any(Function),
    );

    // opened / focused are dropped…
    raw?.({
      payload: { kind: "opened", panel: "git", label: "view-git" },
    });
    raw?.({
      payload: { kind: "focused", panel: "git", label: "view-git" },
    });
    expect(handler).not.toHaveBeenCalled();

    // …only closed reaches the port handler, narrowed to { panel } (#47).
    raw?.({
      payload: { kind: "closed", panel: "git", label: "view-git" },
    });
    expect(handler).toHaveBeenCalledTimes(1);
    expect(handler).toHaveBeenCalledWith({ panel: "git" });

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