import { renderHook } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";

import type { MenuTargetId } from "@/domain";
import type { PluginRuntimeRegistry, WhenContext } from "@/plugins/runtime";
import { usePluginMenus } from "./usePluginMenus";

const NO_CONTEXT: WhenContext = {
  projectOpen: false,
  gitRepository: false,
  agentSelected: false,
  terminalFocused: false,
  layoutCellFocused: false,
};

function throwingRegistry(overrides: Record<string, unknown>): PluginRuntimeRegistry {
  return {
    runCommand: vi.fn(async () => {}),
    topLevelMenus: vi.fn(() => []),
    menuItems: vi.fn(() => []),
    ...overrides,
  } as unknown as PluginRuntimeRegistry;
}

describe("usePluginMenus", () => {
  it("falls back to no plugin top-level menus when plugin menu resolution throws", () => {
    const consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {});
    try {
      const registry = throwingRegistry({
        topLevelMenus: vi.fn(() => {
          throw new Error("broken top-level contribution");
        }),
      });

      const { result } = renderHook(() => usePluginMenus(registry, NO_CONTEXT));

      expect(result.current.topLevelMenus).toEqual([]);
      expect(consoleWarn).toHaveBeenCalledWith(
        "[plugins] menu contribution rejected",
        expect.objectContaining({
          scope: "top-level-menus",
          reason: "broken top-level contribution",
        }),
      );
    } finally {
      consoleWarn.mockRestore();
    }
  });

  it("falls back to no plugin items for a native menu when item resolution throws", () => {
    const consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {});
    try {
      const registry = throwingRegistry({
        menuItems: vi.fn(() => {
          throw new Error("broken item contribution");
        }),
      });

      const { result } = renderHook(() => usePluginMenus(registry, NO_CONTEXT));
      const items = result.current.itemsFor("panels" as MenuTargetId);

      expect(items).toEqual([]);
      expect(consoleWarn).toHaveBeenCalledWith(
        "[plugins] menu contribution rejected",
        expect.objectContaining({
          scope: "items",
          targetMenuId: "panels",
          reason: "broken item contribution",
        }),
      );
    } finally {
      consoleWarn.mockRestore();
    }
  });
});
