/**
 * `usePluginMenus` — turns the loaded plugin runtime registry into ready-to-
 * splice `MenuBarMenu`/`MenuBarItem` entries for `ProjectsView`'s menu bar
 * (ticket #43, F3, carnet §7.1/§7.2).
 *
 * `whenCtx` is supplied by the caller (`ProjectsView` knows `projectOpen`
 * directly; git/agent/terminal/cell-focus signals are best-effort — see the
 * F3 gap noted in the delivery report: there is no existing global
 * agent-selected/terminal-focused/layout-cell-focused signal at the menu-bar
 * level in this codebase today, so those three default to `false` until a
 * future lot threads real focus state up to this level).
 */

import { useMemo } from "react";

import type { MenuTargetId } from "@/domain";
import type { MenuBarItem, MenuBarMenu } from "@/shared";
import type { PluginRuntimeRegistry, WhenContext } from "@/plugins/runtime";
import { resolveMenuItems, resolveTopLevelMenus, type ResolvedTopLevelMenu } from "./menus";

export interface UsePluginMenusResult {
  /** Top-level plugin menus, in order, ready to splice between Panneaux/Paramètres. */
  topLevelMenus: MenuBarMenu[];
  /** Resolved+ordered `MenuBarItem`s to append to a native menu's items. */
  itemsFor: (targetMenuId: MenuTargetId) => MenuBarItem[];
  runCommand: (pluginId: string, commandId: string) => Promise<void>;
}

function describeError(e: unknown): string {
  if (e && typeof e === "object" && "message" in e) {
    return String((e as { message: unknown }).message);
  }
  return String(e);
}

function rejectPluginMenuContribution(
  scope: string,
  details: Record<string, unknown>,
  error: unknown,
): void {
  console.warn("[plugins] menu contribution rejected", {
    scope,
    ...details,
    reason: describeError(error),
  });
}

export function usePluginMenus(
  registry: PluginRuntimeRegistry,
  whenCtx: WhenContext,
): UsePluginMenusResult {
  const runCommand = useMemo(
    () => (pluginId: string, commandId: string) => registry.runCommand(pluginId, commandId),
    [registry],
  );

  const itemsFor = useMemo(() => {
    return (targetMenuId: MenuTargetId): MenuBarItem[] => {
      let resolved;
      try {
        resolved = resolveMenuItems(registry, targetMenuId, whenCtx);
      } catch (e) {
        rejectPluginMenuContribution("items", { targetMenuId }, e);
        return [];
      }

      return resolved.flatMap((item) => {
        try {
          return [
            {
              id: item.id,
              // Provenance is shown discreetly (carnet §0 UX decision) rather than
              // with a visual section divider, which the shared `MenuBar` primitive
              // doesn't support — a trailing "· Plugin Name" suffix is the least
              // intrusive option that still surfaces where the item came from.
              label: `${item.label} · ${item.pluginDisplayName}`,
              disabled: !item.enabled,
              onSelect: () => {
                void runCommand(item.pluginId, item.command);
              },
            },
          ];
        } catch (e) {
          rejectPluginMenuContribution(
            "item",
            {
              pluginId: item.pluginId,
              itemId: item.id,
              targetMenuId,
              commandId: item.command,
            },
            e,
          );
          return [];
        }
      });
    };
  }, [registry, whenCtx, runCommand]);

  const topLevelMenus = useMemo<MenuBarMenu[]>(() => {
    let resolved: ResolvedTopLevelMenu[];
    try {
      resolved = resolveTopLevelMenus(registry);
    } catch (e) {
      rejectPluginMenuContribution("top-level-menus", {}, e);
      return [];
    }

    return resolved.flatMap((menu) => {
      try {
        return [
          {
            id: menu.id,
            label: menu.label,
            items: itemsFor(menu.id),
          },
        ];
      } catch (e) {
        rejectPluginMenuContribution(
          "top-level-menu",
          { pluginId: menu.pluginId, menuId: menu.id },
          e,
        );
        return [];
      }
    });
  }, [registry, itemsFor]);

  return { topLevelMenus, itemsFor, runCommand };
}
