/**
 * Orbit Tiles — Osmo loop, simplified.
 * data-* must not be renamed.
 * Render path: cached medias, quickSetters, caption/status only on change.
 * Position/depth inspired by Osmo Orbit Tiles (radius, depth curve, blur).
 */
import { gsap, ScrollTrigger } from './gsapSetup.js';
import { Draggable } from 'gsap/Draggable';
import { scopeRoot } from './runtime.js';

gsap.registerPlugin(Draggable);

export default function initOrbitTiles(root) {
	const scope = scopeRoot(root);
	const cleanups = [];

	scope.querySelectorAll('[data-orbit-tiles-init]').forEach((container) => {
		if (container.hasAttribute('data-orbit-ready')) return;
		container.setAttribute('data-orbit-ready', 'true');
		const list = container.querySelector('[data-orbit-tiles-list]');
		const tiles = Array.from(container.querySelectorAll('[data-orbit-tiles-item]'));
		const nameEl = container.querySelector('[data-orbit-tiles-caption-name]');
		const textEl = container.querySelector('[data-orbit-tiles-caption-text]');
		const counterEl = container.querySelector('[data-orbit-tiles-counter-current]');
		const counterTotalEl = container.querySelector('[data-orbit-tiles-counter-total]');
		const count = tiles.length;
		if (!list || count < 2) return;

		const CLIP_FROM = 'polygon(46% 46%, 54% 46%, 54% 54%, 46% 54%)';
		const CLIP_TO = 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)';
		const medias = tiles.map((tile) => tile.querySelector('.demo-card__media'));
		const names = tiles.map((tile) => tile.getAttribute('data-orbit-tiles-name') || '');
		const texts = tiles.map((tile) => tile.getAttribute('data-orbit-tiles-text') || '');
		const setX = tiles.map((tile) => gsap.quickSetter(tile, 'x', 'px'));
		const setY = tiles.map((tile) => gsap.quickSetter(tile, 'y', 'px'));
		const setScale = tiles.map((tile) => gsap.quickSetter(tile, 'scale'));
		const setZ = tiles.map((tile) => gsap.quickSetter(tile, 'zIndex'));
		const setFilter = medias.map((media) => (media ? gsap.quickSetter(media, 'filter') : null));

		// Osmo-inspired position / depth
		const radiusXMultiplier = 2.15;
		const radiusYMultiplier = 0;
		const blurMultiplier = 0.04;
		const minScale = 0.2;
		const minDarkness = 0.3;
		const depthPower = 1.3;

		const state = { progress: 0 };
		let target = 0;
		let inView = false;
		let pause;
		let lastActive = -1;
		let cachedWidth = tiles[0].offsetWidth || 1;
		const TWO_PI = Math.PI * 2;
		const invCount = 1 / count;

		if (medias.some(Boolean)) {
			gsap.set(medias.filter(Boolean), { clipPath: CLIP_TO });
		}
		if (counterTotalEl) counterTotalEl.textContent = String(count);

		function wrap(index) {
			return ((index % count) + count) % count;
		}

		function render() {
			const width = cachedWidth;
			const radiusX = width * radiusXMultiplier;
			const radiusY = width * radiusYMultiplier;
			const maxBlur = width * blurMultiplier;
			const active = wrap(Math.round(state.progress));
			const progress = state.progress;

			for (let index = 0; index < count; index++) {
				const angle = (index - progress) * invCount * TWO_PI;
				const depth = ((Math.cos(angle) + 1) * 0.5) ** depthPower;

				setX[index](Math.sin(angle) * radiusX);
				setY[index](Math.cos(angle) * radiusY);
				setScale[index](minScale + (1 - minScale) * depth);
				setZ[index]((depth * 1000 + 0.5) | 0);

				const setF = setFilter[index];
				if (setF) {
					setF(
						`blur(${(1 - depth) * maxBlur}px) brightness(${minDarkness + (1 - minDarkness) * depth})`,
					);
				}
			}

			if (active === lastActive) return;
			lastActive = active;

			for (let index = 0; index < count; index++) {
				tiles[index].setAttribute(
					'data-orbit-tiles-item-status',
					index === active ? 'active' : 'not-active',
				);
			}

			if (nameEl) nameEl.textContent = names[active];
			if (textEl) textEl.textContent = texts[active];
			if (counterEl) counterEl.textContent = String(active + 1);
		}

		function go(next, duration = 0.55) {
			target = next;
			pause?.kill();

			gsap.to(state, {
				progress: next,
				duration,
				ease: 'osmo',
				overwrite: true,
				onUpdate: render,
				onComplete() {
					state.progress = next;
					render();
					if (inView) pause = gsap.delayedCall(1.8, () => go(target + 1, 2.5));
				},
			});
		}

		container.querySelector('[data-orbit-tiles-prev]')?.addEventListener('click', () => {
			go(target - 1);
		});

		container.querySelector('[data-orbit-tiles-next]')?.addEventListener('click', () => {
			go(target + 1);
		});

		const proxy = document.createElement('div');
		let lastX = 0;

		const draggable = Draggable.create(proxy, {
			trigger: list,
			type: 'x',
			zIndexBoost: false,
			onPress() {
				gsap.killTweensOf(state);
				pause?.kill();
				target = state.progress;
				lastX = this.x;
			},
			onDrag() {
				state.progress -= (this.x - lastX) / cachedWidth;
				target = state.progress;
				lastX = this.x;
				render();
			},
			onRelease() {
				go(Math.round(state.progress), 0.7);
			},
		});

		render();

		let resizeRaf = 0;
		const ro = new ResizeObserver(() => {
			if (resizeRaf) return;
			resizeRaf = requestAnimationFrame(() => {
				resizeRaf = 0;
				cachedWidth = tiles[0].offsetWidth || 1;
				render();
			});
		});
		ro.observe(container);

		const reveal = medias.some(Boolean)
			? gsap.fromTo(
					medias.filter(Boolean),
					{ clipPath: CLIP_FROM },
					{
						clipPath: CLIP_TO,
						duration: 1.25,
						ease: 'expo.out',
						paused: true,
						immediateRender: false,
					},
				)
			: null;

		ScrollTrigger.create({
			trigger: container,
			start: 'top bottom',
			end: 'bottom top',
			onEnter() {
				inView = true;
				reveal?.restart(true);
				go(Math.round(state.progress), 0);
			},
			onEnterBack() {
				inView = true;
				go(Math.round(state.progress), 0);
			},
			onLeave() {
				inView = false;
				pause?.kill();
			},
			onLeaveBack() {
				inView = false;
				pause?.kill();
				reveal?.pause(0);
				const visible = medias.filter(Boolean);
				if (visible.length) gsap.set(visible, { clipPath: CLIP_FROM });
			},
		});

		cleanups.push(() => {
			pause?.kill();
			gsap.killTweensOf(state);
			reveal?.kill();
			draggable[0]?.kill();
			ro.disconnect();
			container.removeAttribute('data-orbit-ready');
		});
	});

	if (!cleanups.length) return undefined;

	return () => cleanups.forEach((fn) => fn());
}
