import { For, Show, createSignal, type JSX } from "solid-js";
import { Portal } from "solid-js/web";
import { ChevronRight, Plus, X } from "../../../lib/icons";
import { useAppShellData } from "../data/app-shell.context";
import { createLongPressGesture } from "../createLongPressGesture";
import {
	createWorkspaceStaticTarget,
	createWorkspaceSurfaceTarget,
	createWorkspaceTreeTarget,
	getWorkspaceItemTypeDefinition,
	getWorkspaceNodeIcon,
	workspaceStaticItems,
	type SidebarItem,
	type WorkspaceContextMenuAction,
	type WorkspaceContextMenuTarget,
	type WorkspaceItemTypeId,
	type WorkspaceStaticItem,
	type WorkspaceTreeNode,
} from "../data/shell.data";
import { useWorkspaceTreeData } from "../shared/useWorkspaceTreeData";
import { WorkspaceMobileActionSheet } from "../WorkspaceMobileActionSheet/WorkspaceMobileActionSheet";
import styles from "./MobileWorkspaceBrowser.module.scss";

type MobileWorkspaceBrowserProps = {
	open: boolean;
	onClose: VoidFunction;
};

type MobileWorkspaceDialogState =
	| {
			kind: "text";
			title: string;
			message: string;
			confirmLabel: string;
			initialValue: string;
			onConfirm: (value: string) => void;
	  }
	| {
			kind: "confirm";
			title: string;
			message: string;
			confirmLabel: string;
			tone?: "danger";
			onConfirm: () => void;
	  };

type MobileMoveTargetState = {
	kind: "folder" | "item";
	id: string;
	label: string;
};

type MobileMoveDestination = {
	id: string | null;
	label: string;
	depth: number;
	meta?: string;
};

const collectMoveDestinations = (
	nodes: readonly WorkspaceTreeNode[],
	movingTarget: MobileMoveTargetState,
	depth = 0,
	ancestorBlocked = false,
): MobileMoveDestination[] => {
	const destinations: MobileMoveDestination[] = [];

	for (const node of nodes) {
		if (node.kind !== "folder") {
			continue;
		}

		const isBlockedFolder = movingTarget.kind === "folder" && node.id === movingTarget.id;
		if (!ancestorBlocked && !isBlockedFolder) {
			destinations.push({
				id: node.id,
				label: node.label,
				depth,
				meta: "Folder",
			});
		}

		destinations.push(
			...collectMoveDestinations(node.children ?? [], movingTarget, depth + 1, ancestorBlocked || isBlockedFolder),
		);
	}

	return destinations;
};

const findTreeNodeById = (nodes: readonly WorkspaceTreeNode[], nodeId: string): WorkspaceTreeNode | null => {
	for (const node of nodes) {
		if (node.id === nodeId) {
			return node;
		}

		if (node.kind !== "folder") {
			continue;
		}

		const nestedMatch = findTreeNodeById(node.children ?? [], nodeId);
		if (nestedMatch) {
			return nestedMatch;
		}
	}

	return null;
};

const isDangerDialogState = (state: MobileWorkspaceDialogState): boolean => state.kind === "confirm" && state.tone === "danger";

const TreeRow = (props: { node: WorkspaceTreeNode; depth?: number }): JSX.Element => {
	const depth = props.depth ?? 0;
	const Icon = getWorkspaceNodeIcon(props.node);
	const hasChildren = (props.node.children?.length ?? 0) > 0;

	return (
		<button
			classList={{
				[styles.treeRow]: true,
				[styles.treeRowActive]: props.node.active ?? false,
				[styles.treeRowBranch]: hasChildren,
			}}
			type="button"
			style={{ "--tree-depth": `${depth}` }}
			data-slot="mobile-workspace-tree-row"
			data-kind={props.node.kind}
			data-item-type={props.node.kind === "item" ? props.node.itemType : undefined}
			data-active={props.node.active ? "true" : "false"}
		>
			<span class={styles.treeRowLead}>
				<Icon size={16} strokeWidth={2} />
				<span class={styles.treeLabel}>{props.node.label}</span>
			</span>

			<span class={styles.treeRowTrail}>
				<Show when={props.node.meta}>
					<span class={styles.treeMeta}>{props.node.meta}</span>
				</Show>
				<Show when={hasChildren}>
					<ChevronRight size={14} strokeWidth={2} class={styles.treeChevron} />
				</Show>
			</span>
		</button>
	);
};

const StaticRow = (props: { item: SidebarItem }): JSX.Element => {
	const Icon = props.item.icon;

	return (
		<button classList={{ [styles.treeRow]: true, [styles.treeRowActive]: props.item.active ?? false }} type="button" style={{ "--tree-depth": "0" }} data-slot="mobile-workspace-static-row" data-active={props.item.active ? "true" : "false"}>
			<span class={styles.treeRowLead}>
				<Icon size={16} strokeWidth={2} />
				<span class={styles.treeLabel}>{props.item.label}</span>
			</span>
			<span class={styles.treeRowTrail}>
				<Show when={props.item.meta}>
					<span class={styles.treeMeta}>{props.item.meta}</span>
				</Show>
				<ChevronRight size={14} strokeWidth={2} class={styles.treeChevron} />
			</span>
		</button>
	);
};

const WorkspaceStaticRow = (props: {
	item: WorkspaceStaticItem;
	onOpenActionSheet: (target: WorkspaceContextMenuTarget) => void;
}): JSX.Element => {
	const target = createWorkspaceStaticTarget(props.item);
	const longPress = createLongPressGesture({
		onLongPress: () => {
			props.onOpenActionSheet(target);
		},
	});

	return (
		<li
			class={styles.treeListItem}
			data-slot="mobile-workspace-static-item"
			data-target-kind={target.kind}
			onContextMenu={(event): void => {
				event.preventDefault();
				props.onOpenActionSheet(target);
			}}
			{...longPress}
		>
			<StaticRow item={props.item} />
		</li>
	);
};

const WorkspaceTreeBranch = (props: {
	nodes: readonly WorkspaceTreeNode[];
	depth?: number;
	onOpenActionSheet: (target: WorkspaceContextMenuTarget) => void;
}): JSX.Element => {
	const depth = props.depth ?? 0;

	return (
		<For each={props.nodes}>
			{(node): JSX.Element => {
				const target = createWorkspaceTreeTarget(node);
				const longPress = createLongPressGesture({
					onLongPress: () => {
						props.onOpenActionSheet(target);
					},
				});

				return (
					<li
						class={styles.treeListItem}
						data-slot="mobile-workspace-tree-item"
						data-kind={node.kind}
						data-item-type={node.kind === "item" ? node.itemType : undefined}
						onContextMenu={(event): void => {
							event.preventDefault();
							props.onOpenActionSheet(target);
						}}
						{...longPress}
					>
						<TreeRow node={node} depth={depth} />

						<Show when={node.children?.length}>
							<ul class={styles.treeListNested}>
								<WorkspaceTreeBranch nodes={node.children ?? []} depth={depth + 1} onOpenActionSheet={props.onOpenActionSheet} />
							</ul>
						</Show>
					</li>
				);
			}}
		</For>
	);
};

export const MobileWorkspaceBrowser = (props: MobileWorkspaceBrowserProps): JSX.Element => {
	const appShellData = useAppShellData();
	const [actionSheetTarget, setActionSheetTarget] = createSignal<WorkspaceContextMenuTarget | null>(null);
	const [dialogState, setDialogState] = createSignal<MobileWorkspaceDialogState | null>(null);
	const [dialogValue, setDialogValue] = createSignal("");
	const [moveTarget, setMoveTarget] = createSignal<MobileMoveTargetState | null>(null);
	const { workspaceTreeNodes, createFolder, renameFolder, deleteFolder, moveFolder, createItem, deleteItem, moveItem } = useWorkspaceTreeData({
		activeProjectId: () => appShellData.activeProject().id,
		fallbackWorkspaceTree: () => appShellData.workspaceTree(),
	});
	const workspaceTarget = () => createWorkspaceSurfaceTarget(appShellData.activeProject());

	const moveDestinations = () => {
		const target = moveTarget();
		if (!target) {
			return [] as MobileMoveDestination[];
		}

		return [
			{ id: null, label: "Items root", depth: 0, meta: "Root" },
			...collectMoveDestinations(workspaceTreeNodes(), target),
		];
	};

	const resolveCreateItemType = (actionId: string): WorkspaceItemTypeId | null => {
		switch (actionId) {
			case "create-doc":
				return "core.doc";
			case "create-board":
				return "core.board.kanban";
			case "create-list-board":
				return "core.board.list";
			default:
				return null;
		}
	};

	const createPersistedItem = (itemType: WorkspaceItemTypeId, parentId: string | null): void => {
		const definition = getWorkspaceItemTypeDefinition(itemType);
		void createItem(definition.defaultCreateLabel, itemType, parentId);
	};

	const openActionSheet = (target: WorkspaceContextMenuTarget): void => {
		setActionSheetTarget(target);
	};

	const closeActionSheet = (): void => {
		setActionSheetTarget(null);
	};

	const closeMoveSheet = (): void => {
		setMoveTarget(null);
	};

	const openWorkspaceActionSheet = (): void => {
		openActionSheet(workspaceTarget());
	};

	const closeDialog = (): void => {
		setDialogState(null);
		setDialogValue("");
	};

	const openMoveSheet = (target: MobileMoveTargetState): void => {
		setMoveTarget(target);
	};

	const openTextDialog = (config: Omit<Extract<MobileWorkspaceDialogState, { kind: "text" }>, "kind">): void => {
		setDialogValue(config.initialValue);
		setDialogState({ kind: "text", ...config });
	};

	const openConfirmDialog = (config: Omit<Extract<MobileWorkspaceDialogState, { kind: "confirm" }>, "kind">): void => {
		setDialogValue("");
		setDialogState({ kind: "confirm", ...config });
	};

	const submitDialog = (): void => {
		const state = dialogState();
		if (!state) {
			return;
		}

		if (state.kind === "text") {
			const value = dialogValue().trim();
			if (!value) {
				return;
			}

			closeDialog();
			state.onConfirm(value);
			return;
		}

		closeDialog();
		state.onConfirm();
	};

	const handleMoveDestinationSelect = (destinationId: string | null): void => {
		const target = moveTarget();
		if (!target) {
			return;
		}

		const destinationNode = destinationId ? findTreeNodeById(workspaceTreeNodes(), destinationId) : null;
		const targetIndex = destinationNode?.kind === "folder"
			? destinationNode.children?.length ?? 0
			: destinationId
				? 0
				: workspaceTreeNodes().length;

		closeMoveSheet();

		if (target.kind === "folder") {
			void moveFolder(target.id, destinationId, targetIndex);
			return;
		}

		void moveItem(target.id, destinationId, targetIndex);
	};

	const handleActionSelect = (action: WorkspaceContextMenuAction, target: WorkspaceContextMenuTarget): void => {
		const createItemType = resolveCreateItemType(action.id);
		if (createItemType) {
			switch (target.kind) {
				case "workspace":
				case "home":
					createPersistedItem(createItemType, null);
					return;
				case "folder":
					createPersistedItem(createItemType, target.id);
					return;
				case "settings":
				case "item":
					return;
			}
		}

		switch (action.id) {
			case "new-folder": {
				if (target.kind === "settings" || target.kind === "item") {
					return;
				}

				openTextDialog({
					title: "New folder",
					message: target.kind === "folder" ? `Create a folder inside "${target.label}".` : "Create a folder at the root of Items.",
					confirmLabel: "Create",
					initialValue: "Untitled folder",
					onConfirm: (name) => {
						void createFolder(name, target.kind === "folder" ? target.id : null);
					},
				});
				return;
			}
			case "rename-folder": {
				if (target.kind !== "folder") {
					return;
				}

				openTextDialog({
					title: "Rename folder",
					message: `Update the name for "${target.label}".`,
					confirmLabel: "Save",
					initialValue: target.label,
					onConfirm: (name) => {
						if (name === target.label) {
							return;
						}
						void renameFolder(target.id, name);
					},
				});
				return;
			}
			case "move-folder": {
				if (target.kind !== "folder") {
					return;
				}

				openMoveSheet({
					kind: "folder",
					id: target.id,
					label: target.label,
				});
				return;
			}
			case "delete-folder": {
				if (target.kind !== "folder") {
					return;
				}

				openConfirmDialog({
					title: "Delete folder?",
					message: `"${target.label}" and everything inside it will be removed.`,
					confirmLabel: "Delete",
					tone: "danger",
					onConfirm: () => {
						void deleteFolder(target.id);
					},
				});
				return;
			}
			case "move-doc":
			case "move-board":
			case "move-list-board": {
				if (target.kind !== "item") {
					return;
				}

				openMoveSheet({
					kind: "item",
					id: target.id,
					label: target.label,
				});
				return;
			}
			case "delete-doc":
			case "delete-board":
			case "delete-list-board": {
				if (target.kind !== "item") {
					return;
				}

				openConfirmDialog({
					title: "Delete item?",
					message: `"${target.label}" will be removed from the project tree.`,
					confirmLabel: "Delete",
					tone: "danger",
					onConfirm: () => {
						void deleteItem(target.id);
					},
				});
				return;
			}
			default:
				return;
		}
	};

	const workspaceLongPress = createLongPressGesture({
		onLongPress: openWorkspaceActionSheet,
	});

	return (
		<Show when={props.open}>
			<div class={styles.browserLayer} data-ui="mobile-workspace-browser">
				<section class={styles.sheet} aria-label="Mobile workspace browser" data-slot="mobile-workspace-sheet">
					<header class={styles.sheetHeader} data-slot="mobile-workspace-header">
						<div
							class={styles.brandBlock}
							data-slot="mobile-workspace-brand"
							onContextMenu={(event): void => {
								event.preventDefault();
								openWorkspaceActionSheet();
							}}
							{...workspaceLongPress}
						>
							{/* Long-pressing the browser header exposes workspace-level actions on mobile. */}
							<span class={styles.brandEyebrow}>Moku Work</span>
							<strong class={styles.brandTitle}>{appShellData.activeProject().name}</strong>
							<span class={styles.brandContext}>{appShellData.activeServer().name}</span>
						</div>

						<div class={styles.headerActions} data-slot="mobile-workspace-header-actions">
							<button
								class={styles.createButton}
								type="button"
								aria-label="Create"
								data-slot="mobile-workspace-create"
								onClick={openWorkspaceActionSheet}
							>
								<Plus size={16} strokeWidth={2.25} />
								<span>Create</span>
							</button>

							<button class={styles.closeButton} type="button" aria-label="Close workspace browser" data-slot="mobile-workspace-close" onClick={props.onClose}>
								<X size={18} strokeWidth={2} />
							</button>
						</div>
					</header>

					<div class={styles.sheetBody} data-slot="mobile-workspace-body">
						<section class={styles.sectionBlock} data-slot="mobile-workspace-section" data-section-id="workspace">
							<span class={styles.sectionLabel}>Workspace</span>
							<ul class={styles.treeList} data-slot="mobile-workspace-list" data-section-id="workspace">
								<For each={workspaceStaticItems}>
									{(item): JSX.Element => <WorkspaceStaticRow item={item} onOpenActionSheet={openActionSheet} />}
								</For>
							</ul>
						</section>

						<section class={styles.sectionBlock} data-slot="mobile-workspace-section" data-section-id="items">
							<span class={styles.sectionLabel}>Items</span>
							<ul class={styles.treeList} data-slot="mobile-workspace-list" data-section-id="items">
								<WorkspaceTreeBranch nodes={workspaceTreeNodes()} onOpenActionSheet={openActionSheet} />
							</ul>
						</section>
					</div>
				</section>

				<WorkspaceMobileActionSheet target={actionSheetTarget()} onClose={closeActionSheet} onSelect={handleActionSelect} />

				<Show when={moveTarget()}>
					{(state): JSX.Element => (
						<Portal>
							<div class={styles.moveSheetLayer} data-ui="mobile-workspace-move-sheet">
								<button class={styles.dialogBackdrop} type="button" aria-label="Close move sheet" onClick={closeMoveSheet} />
								<section class={styles.moveSheet} aria-label={`Move ${state().label}`}>
									<div class={styles.moveSheetHandle} aria-hidden="true" />
									<div class={styles.moveSheetHeader}>
										<div class={styles.moveSheetHeaderCopy}>
											<span class={styles.moveSheetEyebrow}>Move {state().kind}</span>
											<strong class={styles.moveSheetTitle}>{state().label}</strong>
											<p class={styles.moveSheetMessage}>Choose a new location in the project tree.</p>
										</div>
									</div>

									<div class={styles.moveSection}>
										<span class={styles.moveSectionLabel}>Destination</span>
										<div class={styles.moveDestinationList}>
											<For each={moveDestinations()}>
												{(destination): JSX.Element => (
													<button
														type="button"
														class={styles.moveDestinationButton}
														style={{ "--move-depth": `${destination.depth}` }}
														onClick={(): void => handleMoveDestinationSelect(destination.id)}
													>
														<span class={styles.moveDestinationLabel}>{destination.label}</span>
														<Show when={destination.meta}>
															<span class={styles.moveDestinationMeta}>{destination.meta}</span>
														</Show>
													</button>
												)}
											</For>
										</div>
									</div>

									<div class={styles.moveSheetFooter}>
										<button class={styles.dialogSecondaryButton} type="button" onClick={closeMoveSheet}>
											Cancel
										</button>
									</div>
								</section>
							</div>
						</Portal>
					)}
				</Show>

				<Show when={dialogState()}>
					{(state): JSX.Element => (
						<Portal>
							<div class={styles.dialogLayer} data-ui="mobile-workspace-dialog">
								<button class={styles.dialogBackdrop} type="button" aria-label="Close dialog" onClick={closeDialog} />
								<section class={styles.dialogCard} aria-label={state().title}>
									<div class={styles.dialogCopy}>
										<strong class={styles.dialogTitle}>{state().title}</strong>
										<p class={styles.dialogMessage}>{state().message}</p>
									</div>

									<Show when={state().kind === "text"}>
										<input
											class={styles.dialogInput}
											type="text"
											value={dialogValue()}
											onInput={(event): void => {
												setDialogValue(event.currentTarget.value);
											}}
											onKeyDown={(event): void => {
												if (event.key === "Enter") {
													event.preventDefault();
													submitDialog();
												}
											}}
											autofocus
										/>
									</Show>

									<div class={styles.dialogActions}>
										<button class={styles.dialogSecondaryButton} type="button" onClick={closeDialog}>
											Cancel
										</button>
										<button
											classList={{
												[styles.dialogPrimaryButton]: true,
												[styles.dialogDangerButton]: isDangerDialogState(state()),
											}}
											type="button"
											onClick={submitDialog}
										>
											{state().confirmLabel}
										</button>
									</div>
								</section>
							</div>
						</Portal>
					)}
				</Show>
			</div>
		</Show>
	);
};
