import { isOSX } from '@theia/core/lib/common/os';
import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution';
import {
  MAIN_MENU_BAR,
  MenuModelRegistry,
  MenuNode,
  MenuPath,
  SubMenuOptions,
} from '@theia/core/lib/common/menu';

export namespace ArduinoMenus {
  // Main menu
  // -- File
  export const FILE__SKETCH_GROUP = [...CommonMenus.FILE, '0_sketch'];
  export const FILE__PRINT_GROUP = [...CommonMenus.FILE, '1_print'];
  // XXX: on macOS, the "Preferences" and "Advanced" group is not under `File`
  // The empty path ensures no top level menu is created for the preferences, even if they contains sub menus
  export const FILE__PREFERENCES_GROUP = [
    ...(isOSX ? [''] : CommonMenus.FILE),
    '2_preferences',
  ];
  export const FILE__ADVANCED_GROUP = [
    ...(isOSX ? [''] : CommonMenus.FILE),
    '3_advanced',
  ];
  export const FILE__ADVANCED_SUBMENU = [
    ...FILE__ADVANCED_GROUP,
    '0_advanced_sub',
  ];

  export const FILE__QUIT_GROUP = [...CommonMenus.FILE, '3_quit'];

  // -- File / Open Recent
  export const FILE__OPEN_RECENT_SUBMENU = [
    ...FILE__SKETCH_GROUP,
    '0_open_recent',
  ];

  // -- File / Sketchbook
  export const FILE__SKETCHBOOK_SUBMENU = [
    ...FILE__SKETCH_GROUP,
    '1_sketchbook',
  ];

  // -- File / Examples
  export const FILE__EXAMPLES_SUBMENU = [...FILE__SKETCH_GROUP, '2_examples'];
  export const EXAMPLES__BUILT_IN_GROUP = [
    ...FILE__EXAMPLES_SUBMENU,
    '0_built_ins',
  ];
  export const EXAMPLES__ANY_BOARD_GROUP = [
    ...FILE__EXAMPLES_SUBMENU,
    '1_any_board',
  ];
  export const EXAMPLES__CURRENT_BOARD_GROUP = [
    ...FILE__EXAMPLES_SUBMENU,
    '2_current_board',
  ];
  export const EXAMPLES__USER_LIBS_GROUP = [
    ...FILE__EXAMPLES_SUBMENU,
    '3_user_libs',
  ];

  // -- Edit
  // `Copy`, `Copy to Forum`, `Paste`, etc.
  // Note: `1_undo` is the first group from Theia, we start with `2`
  export const EDIT__TEXT_CONTROL_GROUP = [
    ...CommonMenus.EDIT,
    '2_text_control',
  ];
  // `Comment/Uncomment`, etc.
  export const EDIT__CODE_CONTROL_GROUP = [
    ...CommonMenus.EDIT,
    '3_code_control',
  ];
  export const EDIT__FONT_CONTROL_GROUP = [
    ...CommonMenus.EDIT,
    '4_font_control',
  ];
  export const EDIT__FIND_GROUP = [...CommonMenus.EDIT, '5_find'];

  // -- Sketch
  export const SKETCH = [...MAIN_MENU_BAR, '3_sketch'];
  export const SKETCH__MAIN_GROUP = [...SKETCH, '0_main'];
  export const SKETCH__UTILS_GROUP = [...SKETCH, '1_utils'];

  // -- Tools
  export const TOOLS = [...MAIN_MENU_BAR, '4_tools'];
  // `Auto Format`, `Archive Sketch`, `Manage Libraries...`, `Serial Monitor`, Serial Plotter
  export const TOOLS__MAIN_GROUP = [...TOOLS, '0_main'];
  // `WiFi101 /  WiFiNINA Firmware Updater`
  export const TOOLS__FIRMWARE_UPLOADER_GROUP = [
    ...TOOLS,
    '1_firmware_uploader',
  ];
  // `Board`, `Port`, and `Get Board Info`.
  export const TOOLS__BOARD_SELECTION_GROUP = [...TOOLS, '2_board_selection'];
  // Core settings, such as `Processor` and `Programmers` for the board and `Burn Bootloader`
  export const TOOLS__BOARD_SETTINGS_GROUP = [...TOOLS, '3_board_settings'];

  // -- Help
  // `Getting Started`, `Environment`, `Troubleshooting`, etc.
  export const HELP__MAIN_GROUP = [...CommonMenus.HELP, '0_main'];
  // `Find in reference`, `FAQ`, etc.
  export const HELP__FIND_GROUP = [...CommonMenus.HELP, '1_find'];
  // `Advanced Mode`.
  // XXX: this will be removed.
  export const HELP__CONTROL_GROUP = [...CommonMenus.HELP, '2_control'];
  // `About` group
  // XXX: on macOS, the about group is not under `Help`
  export const HELP__ABOUT_GROUP = [
    ...(isOSX ? MAIN_MENU_BAR : CommonMenus.HELP),
    '999_about',
  ];

  // ------------

  // Context menus
  // -- Open
  export const OPEN_SKETCH__CONTEXT = ['arduino-open-sketch--context'];
  export const OPEN_SKETCH__CONTEXT__OPEN_GROUP = [
    ...OPEN_SKETCH__CONTEXT,
    '0_open',
  ];
  export const OPEN_SKETCH__CONTEXT__RECENT_GROUP = [
    ...OPEN_SKETCH__CONTEXT,
    '1_recent',
  ];
  export const OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP = [
    ...OPEN_SKETCH__CONTEXT,
    '2_examples',
  ];

  // -- Sketch control
  export const SKETCH_CONTROL__CONTEXT = ['arduino-sketch-control--context'];
  // `New Tab`, `Rename`, `Delete`
  export const SKETCH_CONTROL__CONTEXT__MAIN_GROUP = [
    ...SKETCH_CONTROL__CONTEXT,
    '0_main',
  ];
  // `Previous Tab`, `Next Tab`
  export const SKETCH_CONTROL__CONTEXT__NAVIGATION_GROUP = [
    ...SKETCH_CONTROL__CONTEXT,
    '1_navigation',
  ];
  // Sketch files opened in editors
  export const SKETCH_CONTROL__CONTEXT__RESOURCES_GROUP = [
    ...SKETCH_CONTROL__CONTEXT,
    '2_resources',
  ];

  // -- ROOT SSL CERTIFICATES
  export const ROOT_CERTIFICATES__CONTEXT = [
    'arduino-root-certificates--context',
  ];
}

/**
 * This is a hack. It removes a submenu with all its children if any.
 * Theia cannot dispose submenu entries with a proper API: https://github.com/eclipse-theia/theia/issues/7299
 */
export function unregisterSubmenu(
  menuPath: string[],
  menuRegistry: MenuModelRegistry
): void {
  if (menuPath.length < 2) {
    throw new Error(
      `Expected at least two item as a menu-path. Got ${JSON.stringify(
        menuPath
      )} instead.`
    );
  }
  const toRemove = menuPath[menuPath.length - 1];
  const parentMenuPath = menuPath.slice(0, menuPath.length - 1);
  // This is unsafe. Calling `getMenu` with a non-existing menu-path will result in a new menu creation.
  // https://github.com/eclipse-theia/theia/issues/7300
  const parent = menuRegistry.getMenu(parentMenuPath);
  const index = parent.children.findIndex(({ id }) => id === toRemove);
  if (index === -1) {
    throw new Error(
      `Could not find menu with menu-path: ${JSON.stringify(menuPath)}.`
    );
  }
  (parent.children as Array<MenuNode>).splice(index, 1);
}

/**
 * Special menu node that is not backed by any commands and is always disabled.
 */
export class PlaceholderMenuNode implements MenuNode {
  constructor(
    protected readonly menuPath: MenuPath,
    readonly label: string,
    protected options: SubMenuOptions = { order: '0' }
  ) {}

  get icon(): string | undefined {
    return this.options?.iconClass;
  }

  get sortString(): string {
    return this.options?.order || this.label;
  }

  get id(): string {
    return [...this.menuPath, 'placeholder'].join('-');
  }
}