import { SvelteComponentTyped } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";

export type CarbonMenuContext = {
  close: (trigger: "escape-key" | "outside-click" | "select") => void;
};

type $RestProps = SvelteHTMLElements["ul"];

type $Props = {
  /**
   * Required. Specify the anchor element to position the menu relative to.
   * @default null
   */
  anchor?: null | HTMLElement;

  /**
   * Set the preferred direction of the menu.
   * The menu flips to the opposite direction if there is not enough space.
   * @default "bottom"
   */
  direction?: "bottom" | "top" | "left" | "right";

  /**
   * Set to `true` to open the menu.
   * @default false
   */
  open?: boolean;

  /**
   * Obtain a reference to the unordered list HTML element.
   * @default null
   */
  ref?: null | HTMLUListElement;

  /**
   * Accessible name for the menu.
   * Prefer setting this (or `aria-label`) when there is no visible trigger
   * text for `aria-labelledby`.
   * @default undefined
   */
  labelText?: string | undefined;

  /**
   * Vertical gap in pixels when direction is top.
   * @default 0
   */
  gapTop?: number;

  /**
   * Vertical gap in pixels when direction is bottom.
   * @default 0
   */
  gapBottom?: number;

  /**
   * Horizontal gap in pixels when direction is left.
   * @default 0
   */
  horizontalGapLeft?: number;

  /**
   * Horizontal gap in pixels when direction is right.
   * @default 0
   */
  horizontalGapRight?: number;

  /**
   * Vertical offset in pixels when direction is left.
   * @default 0
   */
  verticalAlignOffsetLeft?: number;

  /**
   * Vertical offset in pixels when direction is right.
   * @default 0
   */
  verticalAlignOffsetRight?: number;

  /**
   * Specify the z-index of the menu.
   * @default 9200
   */
  zIndex?: number;

  /**
   * Specify the size of the menu, which controls each item's row height.
   * `"xs"` has no Carbon v10 equivalent and is hand-authored (see `css/_menu-xs.scss`).
   * @default "sm"
   */
  size?: "xs" | "sm" | "md" | "lg";

  /**
   * Set to `true` to use the menu's intrinsic width instead of matching the anchor width.
   * @default false
   */
  intrinsicWidth?: boolean;

  /**
   * When `intrinsicWidth` is true, align the menu to the anchor.
   * @default "center"
   */
  intrinsicAlign?: "start" | "center" | "end";

  /**
   * DOM node to mount the menu into.
   * When unset, uses the anchor's nearest `<dialog>` or `[popover]`, else `document.body`.
   * @default null
   */
  target?: HTMLElement | null;

  children?: (this: void) => void;

  [key: `data-${string}`]: unknown;
};

export type MenuProps = Omit<$RestProps, keyof $Props> & $Props;

export default class Menu extends SvelteComponentTyped<
  MenuProps,
  {
    close: CustomEvent<{
        trigger: "escape-key" | "outside-click" | "select";
      }>;
    keydown: WindowEventMap["keydown"];
    mouseenter: WindowEventMap["mouseenter"];
    mouseleave: WindowEventMap["mouseleave"];
    open: CustomEvent<HTMLElement>;
  },
  { default: Record<string, never> }
> {}
