// Body scroll-lock for open dialogs/sheets. While any locker is active, the
// document body can't scroll behind the overlay. Ref-counted so that nested or
// stacked dialogs (e.g. a ConfirmSheet opened from the LightboxModal) don't let
// the first one to close unlock the page out from under the others. Compensates
// for the vanished scrollbar width so the layout doesn't jump on lock.

import type { ActionReturn } from 'svelte/action';

let lockCount = 0;
let savedOverflow = '';
let savedPaddingRight = '';

function lock() {
	if (typeof document === 'undefined') return;
	if (lockCount === 0) {
		const body = document.body;
		const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
		savedOverflow = body.style.overflow;
		savedPaddingRight = body.style.paddingRight;
		body.style.overflow = 'hidden';
		if (scrollbarWidth > 0) {
			const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
			body.style.paddingRight = `${current + scrollbarWidth}px`;
		}
	}
	lockCount++;
}

function unlock() {
	if (typeof document === 'undefined') return;
	lockCount = Math.max(0, lockCount - 1);
	if (lockCount === 0) {
		document.body.style.overflow = savedOverflow;
		document.body.style.paddingRight = savedPaddingRight;
	}
}

/**
 * Locks body scroll for the lifetime of the node. Mount the node only while the
 * dialog is open (e.g. inside `{#if open}` or alongside a `class:` toggle) so the
 * action's create/destroy line up with open/close.
 */
export function scrollLock(_node: HTMLElement): ActionReturn {
	lock();
	return {
		destroy() {
			unlock();
		}
	};
}
