import { getMindmapActionMapping, listMindmapActionMappings, type MindmapActionTarget } from "./mindmap-action-map";
import { mindmapDefaultUiSchema, type MindmapUiActionId } from "./mindmap-ui-schema";

export type MindmapRuntimeCapability = MindmapActionTarget;

export type MindmapChromeVisibilityState =
  | "visible"
  | "hiddenByPointerLeave"
  | "hiddenByToggle"
  | "hiddenByFullscreen";

export type MindmapToolbarOverflowState = {
  availableWidth: number | null;
  visibleActionIds: MindmapUiActionId[];
  overflowActionIds: MindmapUiActionId[];
  moreOpen: boolean;
};

export type MindmapFullscreenState = {
  mode: "none" | "canvas" | "page";
  isFullscreen: boolean;
  target: "mindmap-root" | "document-body";
  apiAvailable: boolean;
};

export type MindmapSidebarState = {
  triggerVisible: boolean;
  panelOpen: boolean;
  activePanelId: string | null;
  drawerWidth: number;
  collapsedByToggle: boolean;
};

export type MindmapNavigatorState = {
  searchOpen: boolean;
  minimapOpen: boolean;
  readonly: boolean;
  zoomPercent: number;
  mouseBehavior: "leftSelectRightDrag" | "leftDragRightMenu";
};

export type MindmapShellInteractionState = {
  chromeVisibility: MindmapChromeVisibilityState;
  toolbarOverflow: MindmapToolbarOverflowState;
  fullscreen: MindmapFullscreenState;
  sidebar: MindmapSidebarState;
  navigator: MindmapNavigatorState;
};

export type MindmapUiStateInput = {
  activeNodeId?: string | null;
  readonly: boolean;
  runtimeCapabilities?: MindmapRuntimeCapability[];
  shell?: PartialMindmapShellInteractionState;
};

export type MindmapUiState = {
  activeNodeId: string | null;
  readonly: boolean;
  disabledActions: Record<MindmapUiActionId, boolean>;
  shell: MindmapShellInteractionState;
};

export type PartialMindmapShellInteractionState = {
  chromeVisibility?: MindmapChromeVisibilityState;
  toolbarOverflow?: Partial<MindmapToolbarOverflowState>;
  fullscreen?: Partial<MindmapFullscreenState>;
  sidebar?: Partial<MindmapSidebarState>;
  navigator?: Partial<MindmapNavigatorState>;
};

export type MindmapChromeVisibilityEvent =
  | "pointerLeave"
  | "pointerEnter"
  | "restoreClick"
  | "hideToggle"
  | "showToggle"
  | "enterFullscreen"
  | "exitFullscreen";

const allActionIds = (): MindmapUiActionId[] => {
  const ids = [
    ...mindmapDefaultUiSchema.toolbarGroups.flatMap((group) => group.actions),
    ...mindmapDefaultUiSchema.navigatorItems.flatMap((item) => (item.actionId ? [item.actionId] : [])),
    ...mindmapDefaultUiSchema.contextMenuItems.map((item) => item.actionId),
    ...listMindmapActionMappings().map((mapping) => mapping.actionId),
  ];
  return [...new Set(ids)];
};

const normalizeActiveNodeId = (value: string | null | undefined): string | null => {
  const trimmed = value?.trim();
  return trimmed ? trimmed : null;
};

const normalizeZoomPercent = (value: number | undefined): number => {
  if (typeof value !== "number" || !Number.isFinite(value)) return 100;
  return Math.max(10, Math.min(500, Math.round(value)));
};

const unsupportedActionIds = new Set<MindmapUiActionId>([
  "tag",
  "hyperlink",
  "note",
  "image",
  "icon",
  "associativeLine",
  "formula",
  "import",
  "export",
]);

export const createDefaultMindmapShellInteractionState = (
  input: PartialMindmapShellInteractionState = {},
): MindmapShellInteractionState => ({
  chromeVisibility: input.chromeVisibility ?? "visible",
  toolbarOverflow: {
    availableWidth: input.toolbarOverflow?.availableWidth ?? null,
    visibleActionIds: input.toolbarOverflow?.visibleActionIds ?? [],
    overflowActionIds: input.toolbarOverflow?.overflowActionIds ?? [],
    moreOpen: input.toolbarOverflow?.moreOpen ?? false,
  },
  fullscreen: {
    mode: input.fullscreen?.mode ?? "none",
    isFullscreen: input.fullscreen?.isFullscreen ?? false,
    target: input.fullscreen?.target ?? "mindmap-root",
    apiAvailable: input.fullscreen?.apiAvailable ?? true,
  },
  sidebar: {
    triggerVisible: input.sidebar?.triggerVisible ?? true,
    panelOpen: input.sidebar?.panelOpen ?? true,
    activePanelId: input.sidebar?.activePanelId ?? mindmapDefaultUiSchema.sidebarPanels[0]?.id ?? null,
    drawerWidth: input.sidebar?.drawerWidth ?? 300,
    collapsedByToggle: input.sidebar?.collapsedByToggle ?? false,
  },
  navigator: {
    searchOpen: input.navigator?.searchOpen ?? false,
    minimapOpen: input.navigator?.minimapOpen ?? false,
    readonly: input.navigator?.readonly ?? false,
    zoomPercent: normalizeZoomPercent(input.navigator?.zoomPercent),
    mouseBehavior: input.navigator?.mouseBehavior ?? "leftSelectRightDrag",
  },
});

export const reduceMindmapChromeVisibility = (
  state: MindmapChromeVisibilityState,
  event: MindmapChromeVisibilityEvent,
): MindmapChromeVisibilityState => {
  if (event === "pointerLeave") return "hiddenByPointerLeave";
  if (event === "pointerEnter") return state;
  if (event === "restoreClick") return "visible";
  if (event === "hideToggle") return "hiddenByToggle";
  if (event === "showToggle") return "visible";
  if (event === "enterFullscreen") return state === "visible" ? "visible" : "hiddenByFullscreen";
  if (event === "exitFullscreen") return state === "hiddenByFullscreen" ? "visible" : state;
  return state;
};

export const deriveMindmapUiState = (input: MindmapUiStateInput): MindmapUiState => {
  const activeNodeId = normalizeActiveNodeId(input.activeNodeId);
  const capabilities = input.runtimeCapabilities ? new Set<MindmapRuntimeCapability>(input.runtimeCapabilities) : null;
  const disabledActions = {} as Record<MindmapUiActionId, boolean>;
  const shell = createDefaultMindmapShellInteractionState({
    ...input.shell,
    navigator: {
      ...input.shell?.navigator,
      readonly: input.readonly,
    },
  });

  allActionIds().forEach((actionId) => {
    const mapping = getMindmapActionMapping(actionId);
    if (!mapping) {
      disabledActions[actionId] = true;
      return;
    }
    if (mapping.requiresActiveNode && !activeNodeId) {
      disabledActions[actionId] = true;
      return;
    }
    if (input.readonly && !mapping.readonlyAllowed) {
      disabledActions[actionId] = true;
      return;
    }
    if (capabilities && !capabilities.has(mapping.target)) {
      disabledActions[actionId] = true;
      return;
    }
    if (unsupportedActionIds.has(actionId)) {
      disabledActions[actionId] = true;
      return;
    }
    disabledActions[actionId] = false;
  });

  return {
    activeNodeId,
    readonly: input.readonly,
    disabledActions,
    shell,
  };
};
