/**
 * Draggable Marquee (Directional) — Osmo Supply resource.
 * data-draggable-marquee-* must not be renamed.
 * Accepts optional Barba container root; cleans up on leave / re-init.
 */
import { gsap } from 'gsap';
import { Observer } from 'gsap/Observer';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { qsa } from './barbaDom.js';

gsap.registerPlugin(Observer, ScrollTrigger);

const CLEANUP = '_draggableMarqueeCleanup';

function getNumberAttr(el, name, fallback) {
	const value = parseFloat(el.getAttribute(name));
	return Number.isFinite(value) ? value : fallback;
}

function cleanupMarquee(wrapper) {
	if (typeof wrapper[CLEANUP] === 'function') {
		wrapper[CLEANUP]();
		wrapper[CLEANUP] = null;
	}

	wrapper.querySelectorAll('[data-draggable-marquee-clone]').forEach((el) => el.remove());

	const collection = wrapper.querySelector('[data-draggable-marquee-collection]');
	if (collection) gsap.set(collection, { clearProps: 'transform,x' });

	wrapper.setAttribute('data-draggable-marquee-init', '');
}

export function destroyDraggableMarquee(root) {
	qsa('[data-draggable-marquee-init]', root).forEach(cleanupMarquee);
}

function setupMarquee(wrapper) {
	cleanupMarquee(wrapper);

	const collection = wrapper.querySelector('[data-draggable-marquee-collection]');
	const list = wrapper.querySelector('[data-draggable-marquee-list]');
	if (!collection || !list) return false;

	const duration = getNumberAttr(wrapper, 'data-duration', 20);
	const multiplier = getNumberAttr(wrapper, 'data-multiplier', 40);
	const sensitivity = getNumberAttr(wrapper, 'data-sensitivity', 0.01);

	const wrapperWidth = wrapper.getBoundingClientRect().width;
	const listWidth = list.scrollWidth || list.getBoundingClientRect().width;
	if (!wrapperWidth || !listWidth) return false;

	const minRequiredWidth = wrapperWidth + listWidth + 2;
	while (collection.scrollWidth < minRequiredWidth) {
		const listClone = list.cloneNode(true);
		listClone.setAttribute('data-draggable-marquee-clone', '');
		listClone.setAttribute('aria-hidden', 'true');
		collection.appendChild(listClone);
	}

	const wrapX = gsap.utils.wrap(-listWidth, 0);

	gsap.set(collection, { x: 0 });

	const marqueeLoop = gsap.to(collection, {
		x: -listWidth,
		duration,
		ease: 'none',
		repeat: -1,
		paused: true,
		onReverseComplete: () => marqueeLoop.progress(1),
		modifiers: {
			x: (x) => `${wrapX(parseFloat(x))}px`,
		},
	});

	const initialDirectionAttr = (wrapper.getAttribute('data-direction') || 'left').toLowerCase();
	const baseDirection = initialDirectionAttr === 'right' ? -1 : 1;
	const timeScale = { value: baseDirection };

	wrapper.setAttribute('data-direction', baseDirection < 0 ? 'right' : 'left');
	if (baseDirection < 0) marqueeLoop.progress(1);

	function applyTimeScale() {
		marqueeLoop.timeScale(timeScale.value);
		wrapper.setAttribute('data-direction', timeScale.value < 0 ? 'right' : 'left');
	}

	applyTimeScale();

	const marqueeObserver = Observer.create({
		target: wrapper,
		type: 'pointer,touch',
		preventDefault: true,
		debounce: false,
		onChangeX: (observerEvent) => {
			let velocityTimeScale = observerEvent.velocityX * -sensitivity;
			velocityTimeScale = gsap.utils.clamp(-multiplier, multiplier, velocityTimeScale);

			gsap.killTweensOf(timeScale);

			const restingDirection = velocityTimeScale < 0 ? -1 : 1;

			gsap
				.timeline({ onUpdate: applyTimeScale })
				.to(timeScale, { value: velocityTimeScale, duration: 0.1, overwrite: true })
				.to(timeScale, { value: restingDirection, duration: 1.0 });
		},
	});
	marqueeObserver.disable();

	function syncPlayback(self) {
		if (self.isActive) {
			marqueeLoop.resume();
			applyTimeScale();
			marqueeObserver.enable();
			return;
		}

		marqueeLoop.pause();
		marqueeObserver.disable();
	}

	const st = ScrollTrigger.create({
		trigger: wrapper,
		start: 'top bottom',
		end: 'bottom top',
		onEnter: syncPlayback,
		onEnterBack: syncPlayback,
		onLeave: syncPlayback,
		onLeaveBack: syncPlayback,
		onRefresh: syncPlayback,
	});

	syncPlayback(st);

	wrapper[CLEANUP] = () => {
		st.kill(false);
		marqueeObserver.kill();
		marqueeLoop.kill();
		gsap.killTweensOf(timeScale);
	};

	wrapper.setAttribute('data-draggable-marquee-init', 'initialized');
	return true;
}

export default function initDraggableMarquee(root) {
	const wrappers = qsa(
		'[data-draggable-marquee-init]:not([data-draggable-marquee-init="initialized"])',
		root,
	);
	if (!wrappers.length) return Promise.resolve();

	return Promise.all(
		wrappers.map(
			(wrapper) =>
				new Promise((resolve) => {
					const trySetup = (attemptsLeft) => {
						if (setupMarquee(wrapper) || attemptsLeft <= 0) {
							resolve();
							return;
						}
						requestAnimationFrame(() => trySetup(attemptsLeft - 1));
					};
					// Layout can be unsettled right after a Barba swap — retry briefly.
					// ScrollTrigger.refresh is batched in initPageModules after all setups.
					trySetup(10);
				}),
		),
	);
}
