/**
 * Touch Action Button
 *
 * Floating round button for iPad/tablet that provides access to
 * modifier-key actions (Ctrl+M, Ctrl+D, etc.) that aren't available
 * on touch-only devices.
 *
 * Interaction: press and hold to reveal a radial menu around the button.
 * Drag finger to an item and release to activate it.
 * Auto-shown on touch devices only.
 *
 * Smooth animations:
 * - Items stay mounted and animate between (0,0,scale=0) → (dx,dy,scale=1)
 *   via CSS transitions with staggered delays
 * - Labels crossfade with opacity transition
 * - FAB pulses subtly while menu is open
 * - Highlight uses smooth background/scale/shadow transitions
 */

'use client';

import React, { useState, useRef } from 'react';
import { useAtomValue, useSetAtom } from 'jotai';
import { isTouchDeviceAtom } from '../../core/input-store';
import { hasExternalKeyboardAtom } from '../../core/external-keyboard-store';
import { selectedNodeIdsAtom, clearSelectionAtom, addNodesToSelectionAtom } from '../../core/selection-store';
import { nodeKeysAtom } from '../../core/graph-derived';
import { mergeNodesAtom } from '../../core/graph-mutations';
import { duplicateSelectionAtom } from '../../core/clipboard-store';
import { undoAtom, redoAtom, canUndoAtom, canRedoAtom } from '../../core/history-store';
import { openCommandLineAtom } from '../../commands/store';
import { PlusIcon, MergeIcon, DuplicateIcon, SelectAllIcon, SearchIcon, UndoIcon, RedoIcon } from './icons';
import { type ActionItem, FAB_SIZE, ITEM_SIZE, getRadialPositions, getPositionStyles, RadialMenuItem } from './RadialMenu';

export interface TouchActionButtonProps {
	/** Position of the button. Default: 'bottom-left' */
	position?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
	/** Always visible (even on mouse devices). Default: false */
	alwaysVisible?: boolean;
	/** Custom class name for the container */
	className?: string;
	/** Custom styles for the container */
	style?: React.CSSProperties;
	/** Long-press duration in ms before menu opens. Default: 250 */
	holdDelay?: number;
	/** Radius of the radial menu in px. Default: 80 */
	radius?: number;
}

/**
 * Floating action button with press-and-hold radial menu.
 * Hold to reveal actions in a circle, drag to select, release to activate.
 */
export function TouchActionButton({
	position = 'bottom-left',
	alwaysVisible = false,
	className,
	style,
	holdDelay = 250,
	radius = 80,
}: TouchActionButtonProps) {
	const isTouchDevice = useAtomValue(isTouchDeviceAtom);
	const hasExternalKeyboard = useAtomValue(hasExternalKeyboardAtom);
	const [isOpen, setIsOpen] = useState(false);
	const [highlightedId, setHighlightedId] = useState<string | null>(null);

	const selectedNodeIds = useAtomValue(selectedNodeIdsAtom);
	const nodeKeys = useAtomValue(nodeKeysAtom);
	const mergeNodes = useSetAtom(mergeNodesAtom);
	const duplicateSelection = useSetAtom(duplicateSelectionAtom);
	const clearSelection = useSetAtom(clearSelectionAtom);
	const addNodesToSelection = useSetAtom(addNodesToSelectionAtom);
	const openCommandLine = useSetAtom(openCommandLineAtom);
	const undo = useSetAtom(undoAtom);
	const redo = useSetAtom(redoAtom);
	const canUndo = useAtomValue(canUndoAtom);
	const canRedo = useAtomValue(canRedoAtom);

	const holdTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
	const containerRef = useRef<HTMLDivElement>(null);
	const fabCenterRef = useRef<{ x: number; y: number } | null>(null);
	const didOpenRef = useRef(false);

	if (!alwaysVisible && (!isTouchDevice || hasExternalKeyboard)) {
		return null;
	}

	const hasSelection = selectedNodeIds.size > 0;
	const canMerge = selectedNodeIds.size >= 2;

	const actions: ActionItem[] = [
		{ id: 'undo', label: 'Undo', icon: <UndoIcon />, disabled: !canUndo, action: () => undo() },
		{ id: 'redo', label: 'Redo', icon: <RedoIcon />, disabled: !canRedo, action: () => redo() },
		{ id: 'merge', label: 'Merge', icon: <MergeIcon />, disabled: !canMerge, action: () => { if (canMerge) mergeNodes({ nodeIds: Array.from(selectedNodeIds) }); } },
		{ id: 'duplicate', label: 'Duplicate', icon: <DuplicateIcon />, disabled: !hasSelection, action: () => { if (hasSelection) duplicateSelection(); } },
		{ id: 'select-all', label: 'Select All', icon: <SelectAllIcon />, action: () => { clearSelection(); addNodesToSelection(nodeKeys); } },
		{ id: 'search', label: 'Search', icon: <SearchIcon />, action: () => openCommandLine() },
	];

	const itemPositions = getRadialPositions(actions.length, radius, position);

	const clearHoldTimer = () => {
		if (holdTimerRef.current) {
			clearTimeout(holdTimerRef.current);
			holdTimerRef.current = null;
		}
	};

	const getFabCenter = (): { x: number; y: number } | null => {
		const container = containerRef.current;
		if (!container) return null;
		const fab = container.querySelector('[data-fab-button]') as HTMLElement | null;
		if (!fab) return null;
		const rect = fab.getBoundingClientRect();
		return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
	};

	const findClosestItem = (clientX: number, clientY: number): string | null => {
		const center = fabCenterRef.current;
		if (!center) return null;

		let closest: string | null = null;
		let closestDist = Infinity;
		const hitRadius = ITEM_SIZE * 0.75;

		for (let i = 0; i < actions.length; i++) {
			const pos = itemPositions[i];
			const itemX = center.x + pos.dx;
			const itemY = center.y + pos.dy;
			const dist = Math.hypot(clientX - itemX, clientY - itemY);

			if (dist < hitRadius && dist < closestDist && !actions[i].disabled) {
				closest = actions[i].id;
				closestDist = dist;
			}
		}

		return closest;
	};

	const handlePointerDown = (e: React.PointerEvent) => {
		(e.target as HTMLElement).setPointerCapture(e.pointerId);
		fabCenterRef.current = getFabCenter();
		didOpenRef.current = false;

		holdTimerRef.current = setTimeout(() => {
			setIsOpen(true);
			didOpenRef.current = true;
			holdTimerRef.current = null;
		}, holdDelay);
	};

	const handlePointerMove = (e: React.PointerEvent) => {
		if (!didOpenRef.current) return;
		setHighlightedId(findClosestItem(e.clientX, e.clientY));
	};

	const handlePointerUp = (e: React.PointerEvent) => {
		clearHoldTimer();

		if (didOpenRef.current) {
			const id = findClosestItem(e.clientX, e.clientY);
			if (id) {
				const item = actions.find((a) => a.id === id);
				if (item && !item.disabled) item.action();
			}
			setIsOpen(false);
			setHighlightedId(null);
			didOpenRef.current = false;
		} else {
			// Short tap — toggle for accessibility
			clearHoldTimer();
			setIsOpen((o) => {
				if (o) {
					setHighlightedId(null);
					return false;
				}
				didOpenRef.current = true;
				fabCenterRef.current = getFabCenter();
				return true;
			});
		}
	};

	const handlePointerCancel = () => {
		clearHoldTimer();
		setIsOpen(false);
		setHighlightedId(null);
		didOpenRef.current = false;
	};

	const handleItemTap = (item: ActionItem) => {
		if (item.disabled) return;
		item.action();
		setIsOpen(false);
		setHighlightedId(null);
		didOpenRef.current = false;
	};

	const positionStyles = getPositionStyles(position);

	return (
		<div
			ref={containerRef}
			className={className}
			data-no-drag="true"
			style={{
				position: 'absolute',
				...positionStyles,
				zIndex: 100,
				pointerEvents: 'auto',
				...style,
			}}
		>
			{/* Radial menu items — always mounted for smooth transitions */}
			{actions.map((item, i) => (
				<RadialMenuItem
					key={item.id}
					item={item}
					position={itemPositions[i]}
					index={i}
					totalItems={actions.length}
					isOpen={isOpen}
					isHighlighted={highlightedId === item.id}
					onTap={handleItemTap}
				/>
			))}

			{/* Subtle ring that expands behind items when open */}
			<div
				style={{
					position: 'absolute',
					left: FAB_SIZE / 2,
					top: FAB_SIZE / 2,
					width: radius * 2 + ITEM_SIZE,
					height: radius * 2 + ITEM_SIZE,
					borderRadius: '50%',
					transform: isOpen
						? 'translate(-50%, -50%) scale(1)'
						: 'translate(-50%, -50%) scale(0)',
					background: 'radial-gradient(circle, rgba(255,255,255,0.03) 0%, transparent 70%)',
					transition: isOpen
						? 'transform 400ms cubic-bezier(0.34, 1.3, 0.64, 1), opacity 300ms ease'
						: 'transform 250ms ease, opacity 150ms ease',
					opacity: isOpen ? 1 : 0,
					pointerEvents: 'none',
				}}
			/>

			{/* Main FAB button */}
			<button
				data-fab-button="true"
				onPointerDown={handlePointerDown}
				onPointerMove={handlePointerMove}
				onPointerUp={handlePointerUp}
				onPointerCancel={handlePointerCancel}
				aria-label={isOpen ? 'Close actions' : 'Hold for actions'}
				aria-expanded={isOpen}
				data-no-drag="true"
				style={{
					position: 'relative',
					width: FAB_SIZE,
					height: FAB_SIZE,
					borderRadius: '50%',
					border: `1.5px solid ${isOpen ? 'rgba(99,160,255,0.4)' : 'var(--canvas-control-border, rgba(255,255,255,0.15))'}`,
					backgroundColor: isOpen
						? 'var(--canvas-control-active-bg, rgba(59,130,246,0.9))'
						: 'var(--canvas-control-bg, rgba(30,30,30,0.88))',
					color: 'var(--canvas-control-fg, rgba(255,255,255,0.95))',
					display: 'flex',
					alignItems: 'center',
					justifyContent: 'center',
					cursor: 'pointer',
					touchAction: 'none',
					WebkitTapHighlightColor: 'transparent',
					userSelect: 'none',
					backdropFilter: 'blur(16px) saturate(1.5)',
					WebkitBackdropFilter: 'blur(16px) saturate(1.5)',
					padding: 0,
					transition: 'background-color 250ms ease, border-color 250ms ease, transform 350ms cubic-bezier(0.34, 1.3, 0.64, 1), box-shadow 300ms ease',
					transform: isOpen ? 'rotate(45deg) scale(1.05)' : 'rotate(0deg) scale(1)',
					boxShadow: isOpen
						? '0 0 0 4px rgba(59,130,246,0.15), 0 6px 20px rgba(0,0,0,0.35)'
						: '0 4px 12px rgba(0,0,0,0.3)',
				}}
			>
				<PlusIcon />
			</button>
		</div>
	);
}
