/**
 * Mobile bottom-sheet dismissal gestures, hand-rolled on pointer events
 * (no dependency). A Svelte action for the sheet element:
 *
 * - **tap-outside** — a pointer-down anywhere outside the sheet dismisses
 *   it (the sheet is non-modal, so this is a convenience, not a guard);
 * - **swipe-down** — dragging the sheet's `[data-sheet-handle]` grabber
 *   down past a threshold dismisses it. The swipe starts only from the
 *   handle, so it never fights the sheet's own content scrolling.
 *
 * `onDismiss` is re-read on `update`, so a changing handler stays current.
 */

export interface SheetDismissOptions {
	onDismiss: () => void;
}

/** Downward drag distance (px) past which release dismisses the sheet. */
const SWIPE_DISMISS_PX = 80;

export function sheetDismiss(
	node: HTMLElement,
	options: SheetDismissOptions,
): { update(next: SheetDismissOptions): void; destroy(): void } {
	let opts = options;
	const handle = node.querySelector<HTMLElement>("[data-sheet-handle]") ?? node;

	// The sheet stays mounted on desktop but is hidden by a media query
	// (`display: none`); the document-level tap-outside listener fires
	// regardless of that, so it must no-op while the sheet is not shown,
	// or any click would dismiss the current selection. `offsetParent` is
	// unreliable here (it is null for `position: fixed`), so check the
	// computed display directly.
	function isHidden(): boolean {
		return getComputedStyle(node).display === "none";
	}

	function onDocumentPointerDown(event: PointerEvent): void {
		if (isHidden()) return;
		const target = event.target;
		if (target instanceof Node && node.contains(target)) return;
		opts.onDismiss();
	}

	let dragging = false;
	let startY = 0;
	let pointerId = -1;

	function onHandleDown(event: PointerEvent): void {
		dragging = true;
		startY = event.clientY;
		pointerId = event.pointerId;
		handle.setPointerCapture?.(event.pointerId);
	}

	function onPointerMove(event: PointerEvent): void {
		if (!dragging || event.pointerId !== pointerId) return;
		const dy = Math.max(0, event.clientY - startY);
		node.style.transform = dy > 0 ? `translateY(${dy}px)` : "";
	}

	function onPointerUp(event: PointerEvent): void {
		if (!dragging || event.pointerId !== pointerId) return;
		const dy = event.clientY - startY;
		dragging = false;
		node.style.transform = "";
		if (dy > SWIPE_DISMISS_PX) opts.onDismiss();
	}

	document.addEventListener("pointerdown", onDocumentPointerDown, true);
	handle.addEventListener("pointerdown", onHandleDown);
	window.addEventListener("pointermove", onPointerMove);
	window.addEventListener("pointerup", onPointerUp);
	window.addEventListener("pointercancel", onPointerUp);

	return {
		update(next: SheetDismissOptions): void {
			opts = next;
		},
		destroy(): void {
			document.removeEventListener("pointerdown", onDocumentPointerDown, true);
			handle.removeEventListener("pointerdown", onHandleDown);
			window.removeEventListener("pointermove", onPointerMove);
			window.removeEventListener("pointerup", onPointerUp);
			window.removeEventListener("pointercancel", onPointerUp);
		},
	};
}
