/** @jsxImportSource react */
import { cn } from "@nestri/ui/design";
import { qwikify$ } from "@builder.io/qwik-react";
import React, { useEffect, useRef, useState } from "react";
import {
    motion,
    useAnimationFrame,
    useMotionValue,
    useScroll,
    useSpring,
    useTransform,
    useVelocity,
} from "framer-motion";

interface VelocityScrollProps {
    text: string;
    default_velocity?: number;
    class?: string;
}

interface ParallaxProps {
    children: string;
    baseVelocity: number;
    class?: string;
}

export const wrap = (min: number, max: number, v: number) => {
    const rangeSize = max - min;
    return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
};

export function ReactMarquee({
    class: className,
    text,
    default_velocity = 5,
}: VelocityScrollProps) {
    function ParallaxText({
        children,
        baseVelocity = 100,
        class:className,
    }: ParallaxProps) {
        const baseX = useMotionValue(0);
        const { scrollY } = useScroll();
        const scrollVelocity = useVelocity(scrollY);
        const smoothVelocity = useSpring(scrollVelocity, {
            damping: 50,
            stiffness: 400,
        });

        const velocityFactor = useTransform(smoothVelocity, [0, 1000], [0, 5], {
            clamp: false,
        });

        const [repetitions, setRepetitions] = useState(1);
        const containerRef = useRef<HTMLDivElement>(null);
        const textRef = useRef<HTMLSpanElement>(null);

        useEffect(() => {
            const calculateRepetitions = () => {
                if (containerRef.current && textRef.current) {
                    const containerWidth = containerRef.current.offsetWidth;
                    const textWidth = textRef.current.offsetWidth;
                    const newRepetitions = Math.ceil(containerWidth / textWidth) + 2;
                    setRepetitions(newRepetitions);
                }
            };

            calculateRepetitions();

            window.addEventListener("resize", calculateRepetitions);
            return () => window.removeEventListener("resize", calculateRepetitions);
        }, [children]);

        const x = useTransform(baseX, (v) => `${wrap(-100 / repetitions, 0, v)}%`);

        const directionFactor = React.useRef<number>(1);
        useAnimationFrame((t, delta) => {
            let moveBy = directionFactor.current * baseVelocity * (delta / 1000);

            if (velocityFactor.get() < 0) {
                directionFactor.current = -1;
            } else if (velocityFactor.get() > 0) {
                directionFactor.current = 1;
            }

            moveBy += directionFactor.current * moveBy * velocityFactor.get();

            baseX.set(baseX.get() + moveBy);
        });

        return (
            <div
                className="w-full overflow-hidden whitespace-nowrap"
                ref={containerRef}
            >
                <motion.div className={cn("inline-block", className)} style={{ x }}>
                    {Array.from({ length: repetitions }).map((_, i) => (
                        <span key={i} ref={i === 0 ? textRef : null}>
                            {children}{" "}
                        </span>
                    ))}
                </motion.div>
            </div>
        );
    }

    return (
        <section className="relative w-full">
            <ParallaxText baseVelocity={default_velocity} class={className}>
                {text}
            </ParallaxText>
            <ParallaxText baseVelocity={-default_velocity} class={className}>
                {text}
            </ParallaxText>
        </section>
    );
}

export const Marquee = qwikify$(ReactMarquee);