import { useEffect, useRef, useState } from "react";
import type { CurrentModel } from "./ModelsWrapper";
import { onAppFullyReady } from "@/lib/on-app-full-ready";
import { useGSAP } from "@gsap/react";
import gsap from "gsap";

type ModelViewerProps = {
  currentModel: CurrentModel;
};

const FRAME_COUNT = 35;
const FRAME_DURATION = 0.025;

const preloadImages = (urls: string[]): Promise<void> => {
  return new Promise((resolve) => {
    let loaded = 0;

    urls.forEach((src) => {
      const img = new Image();

      img.onload = img.onerror = () => {
        loaded++;
        if (loaded === urls.length) {
          resolve();
        }
      };

      img.src = src;
    });
  });
};

const ModelViewer = ({ currentModel }: ModelViewerProps) => {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const revealDoneRef = useRef(false);

  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;

    const urls = Array.from({ length: FRAME_COUNT }).map((_, i) => `/models/${currentModel}-${i}.webp`);

    setIsLoading(true);

    preloadImages(urls).then(() => {
      if (!cancelled) {
        setIsLoading(false);
      }
    });

    return () => {
      cancelled = true;
    };
  }, [currentModel]);

  useGSAP(
    () => {
      if (!containerRef.current || isLoading) return;

      let ctx: gsap.Context | null = null;
      let framesTl: gsap.core.Timeline | null = null;

      const container = containerRef.current;

      const isTouchDevice = window.matchMedia("(pointer: coarse)").matches;

      const playFrames = () => framesTl?.play();
      const pauseFrames = () => framesTl?.pause();

      onAppFullyReady(() => {
        ctx = gsap.context(() => {
          if (!revealDoneRef.current) {
            const imageWrapper = container.firstElementChild as HTMLElement | null;

            if (imageWrapper) {
              gsap.set(imageWrapper, {
                clipPath: "inset(0 0 100% round 0.5rem)",
              });

              gsap.to(imageWrapper, {
                clipPath: "inset(0 0 0% round 0.5rem)",
                ease: "expo.inOut",
                duration: 2,
                scrollTrigger: {
                  trigger: container,
                  start: `top ${window.innerWidth > 1023 ? "40%" : "50%"}`,
                },
              });

              revealDoneRef.current = true;
            }
          }

          const frames = gsap.utils.toArray<HTMLImageElement>(container.querySelectorAll(".model-frame"));

          if (!frames.length) return;

          let index = 0;

          gsap.set(frames, { opacity: 0 });
          gsap.set(frames[0], { opacity: 1 });

          framesTl = gsap.timeline({
            repeat: -1,
            paused: true,
            defaults: { ease: "none" },
          });

          framesTl.to(
            {},
            {
              duration: FRAME_DURATION * 4,
              repeat: -1,
              onRepeat: () => {
                frames[index].style.opacity = "0";
                index = (index + 1) % frames.length;
                frames[index].style.opacity = "1";
              },
            },
          );

          if (isTouchDevice) {
            playFrames();
          }
        }, container);
      });

      if (!isTouchDevice) {
        container.addEventListener("mouseenter", playFrames);
        container.addEventListener("mouseleave", pauseFrames);
      }

      return () => {
        if (!isTouchDevice) {
          container.removeEventListener("mouseenter", playFrames);
          container.removeEventListener("mouseleave", pauseFrames);
        }
        framesTl?.kill();
        ctx?.revert();
      };
    },
    { dependencies: [currentModel, isLoading], scope: containerRef },
  );

  return (
    <div ref={containerRef} className="relative lg:w-2/3 aspect-[328/237] lg:aspect-auto rounded-[0.5rem]">
      <div className="relative size-full rounded-[inherit] bg-[#E2E2E2] overflow-hidden">
        {/* {isLoading && (
          <div className="absolute inset-0 z-10 flex items-center justify-center rounded-[inherit] bg-[#E2E2E2]">
            <div className="loader absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 scale-75 text-yoyo-light-blue"></div>
          </div>
        )} */}
        {Array.from({ length: FRAME_COUNT }).map((_, i) => (
          <img
            key={`${currentModel}-${i}`}
            src={`/models/${currentModel}-${i}.webp`}
            alt=""
            className="model-frame absolute inset-0 size-full object-cover opacity-0"
            draggable={false}
          />
        ))}
      </div>
    </div>
  );
};

export default ModelViewer;
