import Lenis from 'lenis';

(() => {
    if (typeof window === 'undefined') return;

    const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    const lenis = prefersReducedMotion
        ? null
        : new Lenis({
            duration: 1.2,
            easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
            orientation: 'vertical',
            gestureOrientation: 'vertical',
            smoothWheel: true,
            wheelMultiplier: 1,
            touchMultiplier: 2,
        });

    if (lenis) {
        function raf(time) {
            lenis.raf(time);
            requestAnimationFrame(raf);
        }
        requestAnimationFrame(raf);
    }

    const heroBackground = document.querySelector('.hero-background') as HTMLElement;

    if (heroBackground && lenis) {
        lenis.on('scroll', ({ scroll }) => {
            const offset = Math.min(scroll * 0.5, 300);
            heroBackground.style.transform = `translate3d(0, ${offset}px, 0)`;
        });
    }

    const revealables = document.querySelectorAll('.revealable');
    if (revealables.length) {
        if ('IntersectionObserver' in window) {
            const observer = new IntersectionObserver((entries) => {
                entries.forEach((entry) => {
                    if (entry.isIntersecting) {
                        entry.target.classList.add('is-visible');
                        observer.unobserve(entry.target);
                    }
                });
            }, { 
                threshold: 0.15,
                rootMargin: "0px 0px -50px 0px"
            });
            revealables.forEach((item) => observer.observe(item));
        } else {
            revealables.forEach((item) => item.classList.add('is-visible'));
        }
    }
    
    document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();
            const href = this.getAttribute('href');
            if (!href) return;

            if (lenis) {
                lenis.scrollTo(href);
                return;
            }

            const target = document.querySelector(href);
            if (target instanceof HTMLElement) {
                target.scrollIntoView({ behavior: 'auto', block: 'start' });
            }
        });
    });

    const graphSection = document.querySelector('.longtail-section');
    const graphPath = document.querySelector('.graph-path') as SVGPathElement;
    const graphPathGold = document.querySelector('.graph-path-gold') as SVGPathElement;
    const points = document.querySelectorAll('.graph-point');
    const labels = document.querySelectorAll('.graph-label');
    const sublabels = document.querySelectorAll('.graph-sublabel');

    if (graphSection && graphPath && graphPathGold) {
        const initGraph = () => {
            let length = 0;
            try {
                length = graphPath.getTotalLength();
            } catch {
                length = 0;
            }

            const showStaticGraph = prefersReducedMotion || !Number.isFinite(length) || length <= 1;
            if (showStaticGraph) {
                graphPath.style.strokeDasharray = 'none';
                graphPath.style.strokeDashoffset = '0';
                graphPathGold.style.strokeDasharray = 'none';
                graphPathGold.style.strokeDashoffset = '0';
                graphPathGold.classList.add('is-active');
                points.forEach((p) => p.classList.add('is-active'));
                labels.forEach((l) => l.classList.add('is-active'));
                sublabels.forEach((s) => s.classList.add('is-active'));
                return;
            }

            graphPath.style.strokeDasharray = `${length} ${length}`;
            graphPath.style.strokeDashoffset = `${length}`;

            graphPathGold.style.strokeDasharray = `${length} ${length}`;
            graphPathGold.style.strokeDashoffset = `${length}`;

            let startY = 0;
            let endY = 1;
            const refreshBounds = () => {
                const rect = graphSection.getBoundingClientRect();
                const top = rect.top + window.scrollY;
                const windowHeight = window.innerHeight;

                // Start when the section is entering the viewport, and finish around when it's centered.
                startY = top - windowHeight * 0.85;
                endY = top + rect.height * 0.5 - windowHeight * 0.5;
                if (endY <= startY) endY = startY + 1;
            };

            const thresholds = [0.15, 0.48, 0.72];

            const applyProgress = (scrollY: number) => {
                const drawProgress = Math.max(0, Math.min(1, (scrollY - startY) / (endY - startY)));
                const dashOffset = Math.max(0, length * (1 - drawProgress));

                graphPath.style.strokeDashoffset = `${dashOffset}`;
                graphPathGold.style.strokeDashoffset = `${dashOffset}`;

                thresholds.forEach((t, i) => {
                    if (drawProgress >= t) {
                        if (points[i]) points[i].classList.add('is-active');
                        if (labels[i]) labels[i].classList.add('is-active');
                    } else {
                        if (points[i]) points[i].classList.remove('is-active');
                        if (labels[i]) labels[i].classList.remove('is-active');
                    }
                });

                if (drawProgress >= 0.72) {
                    graphPathGold.classList.add('is-active');
                } else {
                    graphPathGold.classList.remove('is-active');
                }

                if (drawProgress > 0.3) {
                    if (sublabels[0]) sublabels[0].classList.add('is-active');
                } else {
                    if (sublabels[0]) sublabels[0].classList.remove('is-active');
                }

                if (drawProgress > 0.6) {
                    if (sublabels[1]) sublabels[1].classList.add('is-active');
                } else {
                    if (sublabels[1]) sublabels[1].classList.remove('is-active');
                }
            };

            let ticking = false;
            let latestScroll = window.scrollY;
            const requestUpdate = () => {
                if (ticking) return;
                ticking = true;
                requestAnimationFrame(() => {
                    ticking = false;
                    applyProgress(latestScroll);
                });
            };

            refreshBounds();
            applyProgress(window.scrollY);

            if (lenis) {
                lenis.on('scroll', ({ scroll }) => {
                    latestScroll = scroll;
                    requestUpdate();
                });
            }

            window.addEventListener('scroll', () => {
                latestScroll = window.scrollY;
                requestUpdate();
            }, { passive: true });

            window.addEventListener('resize', () => {
                refreshBounds();
                latestScroll = window.scrollY;
                requestUpdate();
            });
        };

        // Android can report 0-length paths until the next frame.
        requestAnimationFrame(() => requestAnimationFrame(initGraph));
    }
})();
