import { For, Show, createEffect, createMemo, createSignal, onMount, type JSX } from "solid-js";
import { Portal } from "solid-js/web";
import { ChevronRight, Plus } from "../../../lib/icons";
import {
	getWorkspaceContextMenuEyebrow,
	getWorkspaceContextMenuSections,
	type WorkspaceContextMenuAction,
	type WorkspaceContextMenuShortcut,
	type WorkspaceContextMenuTarget,
} from "../data/shell.data";
import styles from "./WorkspaceContextMenu.module.scss";

type ShortcutPlatform = "mac" | "windows";

type NavigatorWithUserAgentData = Navigator & {
	userAgentData?: {
		platform?: string;
	};
};

type WorkspaceContextMenuPosition = {
	x: number;
	y: number;
};

type WorkspaceContextMenuProps = {
	target: WorkspaceContextMenuTarget | null;
	position: WorkspaceContextMenuPosition | null;
	onClose: VoidFunction;
	onSelect: (action: WorkspaceContextMenuAction, target: WorkspaceContextMenuTarget) => void;
	menuRef: (element: HTMLDivElement) => void;
};

const getShortcutPlatform = (): ShortcutPlatform => {
	if (typeof navigator === "undefined") {
		return "mac";
	}

	const navigatorWithUserAgentData = navigator as NavigatorWithUserAgentData;

	const platform =
		typeof navigatorWithUserAgentData.userAgentData?.platform === "string"
			? navigatorWithUserAgentData.userAgentData.platform
			: navigator.platform;

	return /mac|iphone|ipad|ipod/i.test(platform) ? "mac" : "windows";
};

const formatShortcut = (shortcut: WorkspaceContextMenuShortcut, platform: ShortcutPlatform): string => {
	const keyLabel = (() => {
		switch (shortcut.key) {
			case "enter":
				return platform === "mac" ? "↩" : "Enter";
			case "delete":
				return platform === "mac" ? "⌫" : "Del";
			default:
				return shortcut.key.toUpperCase();
		}
	})();

	const modifierLabels =
		shortcut.modifiers?.map((modifier) => {
			switch (modifier) {
				case "meta":
					return platform === "mac" ? "⌘" : "Ctrl";
				case "alt":
					return platform === "mac" ? "⌥" : "Alt";
				case "shift":
					return platform === "mac" ? "⇧" : "Shift";
			}
		}) ?? [];

	if (platform === "mac") {
		return `${modifierLabels.join("")}${keyLabel}`;
	}

	return [...modifierLabels, keyLabel].join("+");
};

export const WorkspaceContextMenu = (props: WorkspaceContextMenuProps): JSX.Element => {
	const [activeSubmenuActionId, setActiveSubmenuActionId] = createSignal<string | null>(null);
	const [shortcutPlatform, setShortcutPlatform] = createSignal<ShortcutPlatform>("mac");
	const sections = createMemo(() => (props.target ? getWorkspaceContextMenuSections(props.target) : []));
	const handleActionSelect = (action: WorkspaceContextMenuAction, target: WorkspaceContextMenuTarget): void => {
		props.onSelect(action, target);
		props.onClose();
	};
	const menuState = createMemo<{
		target: WorkspaceContextMenuTarget;
		position: WorkspaceContextMenuPosition;
	} | null>(() =>
		props.target && props.position
			? {
				target: props.target,
				position: props.position,
			}
			: null,
	);
	const showHeader = (): boolean => props.target?.kind !== "workspace";
	const sectionHasLabel = createMemo(() => sections().some((section) => Boolean(section.label)));

	onMount(() => {
		setShortcutPlatform(getShortcutPlatform());
	});

	createEffect(() => {
		void props.target;
		setActiveSubmenuActionId(null);
	});

	return (
		<Show when={menuState()}>
			{(resolvedMenuState): JSX.Element => {
				const target = resolvedMenuState().target;
				const position = resolvedMenuState().position;

				return (
					<Portal>
						<div
							ref={props.menuRef}
							class={styles.menu}
							role="menu"
							aria-label={`${target.label} context menu`}
							data-ui="workspace-context-menu"
							data-target-kind={target.kind}
							data-item-type={target.kind === "item" ? target.itemType : undefined}
							style={{
								left: `${position.x}px`,
								top: `${position.y}px`,
							}}
						>
							<Show when={target.kind !== "workspace"}>
								<header class={styles.header} data-slot="context-menu-header">
									<span class={styles.eyebrow}>{getWorkspaceContextMenuEyebrow(target)}</span>
									<strong class={styles.title}>{target.label}</strong>
								</header>
							</Show>

							<div classList={{ [styles.sectionList]: true, [styles.sectionListCompact]: !sectionHasLabel() }} data-slot="context-menu-sections">
								<For each={sections()}>
									{(section): JSX.Element => (
											<section class={styles.section} data-slot="context-menu-section" data-section-id={section.id}>
												<Show when={section.label}>
													<span class={styles.sectionLabel}>{section.label}</span>
												</Show>

												<div class={styles.actionList} data-slot="context-menu-action-list">
													<For each={section.items}>
														{(action): JSX.Element => {
															const isSubmenuOpen = () => activeSubmenuActionId() === action.id;

															return (
														<div
															class={styles.actionItem}
															data-slot="context-menu-action-item"
															data-action-id={action.id}
															onMouseEnter={() => {
																		setActiveSubmenuActionId(action.children ? action.id : null);
																	}}
																>
															<button
																type="button"
																role="menuitem"
																		classList={{
																			[styles.action]: true,
																			[styles.actionCreate]: action.id === "create",
																	[styles.actionDanger]: action.tone === "danger",
																	[styles.actionSubmenuOpen]: isSubmenuOpen(),
																}}
																data-slot="context-menu-action"
																data-action-id={action.id}
																data-tone={action.tone ?? "default"}
															onClick={() => {
																if (action.children) {
																	setActiveSubmenuActionId(isSubmenuOpen() ? null : action.id);
																	return;
																}

																handleActionSelect(action, target);
															}}
														>
																		<Show when={action.id === "create"}>
																			<span class={styles.actionCreateIcon} aria-hidden="true">
																				<Plus size={14} strokeWidth={2.25} />
																			</span>
																		</Show>
																		<span class={styles.actionLabel}>{action.label}</span>
																		<div class={styles.actionMeta}>
																			<Show when={action.shortcut}>
																				<span class={styles.actionShortcut}>{formatShortcut(action.shortcut!, shortcutPlatform())}</span>
																			</Show>
																			<Show when={action.children}>
																				<ChevronRight class={styles.actionChevron} size={16} strokeWidth={2} />
																			</Show>
																		</div>
																	</button>

																	<Show when={action.children && isSubmenuOpen()}>
																<div class={styles.submenu} role="menu" aria-label={`${action.label} submenu`} data-slot="context-menu-submenu">
																	<div class={styles.submenuList} data-slot="context-menu-submenu-list">
																				<For each={action.children ?? []}>
																					{(childAction): JSX.Element => (
																			<button
																				type="button"
																				role="menuitem"
																	classList={{
																					[styles.action]: true,
																					[styles.actionDanger]: childAction.tone === "danger",
																				}}
																				data-slot="context-menu-submenu-action"
																				data-action-id={childAction.id}
																				data-tone={childAction.tone ?? "default"}
																				onClick={() => handleActionSelect(childAction, target)}
																>
																							<span class={styles.actionLabel}>{childAction.label}</span>
																							<div class={styles.actionMeta}>
																								<Show when={childAction.shortcut}>
																									<span class={styles.actionShortcut}>{formatShortcut(childAction.shortcut!, shortcutPlatform())}</span>
																								</Show>
																							</div>
																						</button>
																					)}
																				</For>
																			</div>
																		</div>
																	</Show>
																</div>
															);
														}}
													</For>
												</div>
											</section>
										)}
								</For>
							</div>
						</div>
					</Portal>
				);
			}}
		</Show>
	);
};
