"use client";

import { useLayoutEffect, useRef, useState } from "react";
import { motion, useAnimationFrame, useMotionValue, useReducedMotion } from "framer-motion";

import { cn } from "@/lib/utils";

type MarqueeDirection = "left" | "right";

export type MarqueeRow = {
  items: string[];
  direction: MarqueeDirection;
  duration?: number;
};

type StackedMarqueeSectionProps = {
  className?: string;
  rows?: MarqueeRow[];
};

const DEFAULT_ROWS: MarqueeRow[] = [
  {
    direction: "left",
    duration: 126,
    items: [
      "Next.js",
      "React",
      "WordPress",
      "Docker",
      "Technical SEO",
      "Tailwind CSS",
      "Google Analytics",
      "Framer Motion",
      "Cloudflare",
      "Performance",
    ],
  },
  {
    direction: "right",
    duration: 220,
    items: [
      "TypeScript",
      "Node.js",
      "WooCommerce",
      "Schema Markup",
      "DevOps",
      "Responsive Design",
      "Core Web Vitals",
      "Plausible Analytics",
      "Design Systems",
      "Server Infrastructure",
    ],
  },
  {
    direction: "left",
    duration: 168,
    items: [
      "JavaScript",
      "REST APIs",
      "Git",
      "Linux",
      "Search Console",
      "Conversion Tracking",
      "UI Engineering",
      "Accessibility",
      "Component Architecture",
      "Web Performance",
    ],
  },
  {
    direction: "right",
    duration: 144,
    items: [
      "Frontend Strategy",
      "CMS Integration",
      "Motion Design",
      "Content Architecture",
      "E-Commerce",
      "SEO Audits",
      "Deployments",
      "Scalable UI",
      "Analytics Setup",
      "Product Pages",
    ],
  },
];

function MarqueeRowTrack({
  items,
  direction,
  duration = 24,
}: MarqueeRow) {
  const shouldReduceMotion = useReducedMotion();
  const viewportRef = useRef<HTMLDivElement>(null);
  const segmentRef = useRef<HTMLDivElement>(null);
  const [segmentWidth, setSegmentWidth] = useState(0);
  const [copyCount, setCopyCount] = useState(3);
  const x = useMotionValue(0);
  const isReady = shouldReduceMotion || segmentWidth > 0;

  useLayoutEffect(() => {
    const viewport = viewportRef.current;
    const segment = segmentRef.current;

    if (!viewport || !segment) {
      return;
    }

    const measure = () => {
      const nextSegmentWidth = segment.getBoundingClientRect().width;
      const viewportWidth = viewport.clientWidth;

      if (!nextSegmentWidth || !viewportWidth) {
        return;
      }

      setSegmentWidth(nextSegmentWidth);
      setCopyCount(Math.max(3, Math.ceil(viewportWidth / nextSegmentWidth) + 2));
      x.set(direction === "right" ? -nextSegmentWidth : 0);
    };

    measure();

    const observer = new ResizeObserver(() => {
      measure();
    });

    observer.observe(viewport);
    observer.observe(segment);

    return () => {
      observer.disconnect();
    };
  }, [direction, items, x]);

  useAnimationFrame((_, delta) => {
    if (shouldReduceMotion || segmentWidth === 0) {
      return;
    }

    const distancePerMs = segmentWidth / (duration * 1000);
    const offset = distancePerMs * delta;
    const current = x.get();

    if (direction === "right") {
      const next = current + offset;
      x.set(next >= 0 ? next - segmentWidth : next);
      return;
    }

    const next = current - offset;
    x.set(next <= -segmentWidth ? next + segmentWidth : next);
  });

  return (
    <div
      ref={viewportRef}
      dir="ltr"
      className="w-full overflow-hidden font-latin leading-[0.92]"
    >
      <motion.div
        dir="ltr"
        className={cn("flex w-max flex-nowrap", !isReady && "opacity-0")}
        style={{ x }}
      >
        {Array.from({ length: copyCount }).map((_, copyIndex) => (
          <div
            key={`${direction}-${copyIndex}`}
            ref={copyIndex === 0 ? segmentRef : undefined}
            className="flex shrink-0 items-center gap-3 pr-3 sm:gap-4 sm:pr-4 lg:gap-5 lg:pr-5"
            aria-hidden={copyIndex > 0}
            dir="ltr"
          >
            {items.map((item, itemIndex) => (
              <div
                key={`${copyIndex}-${item}`}
                className="flex shrink-0 items-center gap-3 sm:gap-4 lg:gap-5"
                dir="ltr"
              >
                <span
                  className={cn(
                    "shrink-0 whitespace-nowrap text-[clamp(2.05rem,6vw,4.8rem)] uppercase leading-[0.92] tracking-[-0.01em] text-[hsl(var(--surface-3))] dark:text-[hsl(var(--surface-3))] [text-shadow:0_1px_2px_hsl(222_24%_10%_/_0.06)]",
                    itemIndex % 2 === 0 ? "font-black" : "font-light",
                  )}
                >
                  {item}
                </span>
                <span
                  className="text-[clamp(1.85rem,5vw,4rem)] font-light leading-[0.92] tracking-[-0.01em] text-[hsl(var(--surface-3))] dark:text-[hsl(var(--surface-3))] [text-shadow:0_1px_2px_hsl(222_24%_10%_/_0.05)]"
                  aria-hidden="true"
                >
                  /
                </span>
              </div>
            ))}
          </div>
        ))}
      </motion.div>
    </div>
  );
}

export function StackedMarqueeSection({
  className,
  rows = DEFAULT_ROWS,
}: StackedMarqueeSectionProps) {
  return (
    <section
      aria-label="Technology marquee"
      dir="ltr"
      className={cn(
        "relative isolate overflow-hidden bg-transparent py-3 sm:py-4 lg:py-5",
        className,
      )}
    >
      <div className="relative flex flex-col gap-0 sm:gap-0 lg:gap-0">
        {rows.map((row, index) => (
          <div key={`${row.direction}-${index}`} dir="ltr" className="w-full">
            <MarqueeRowTrack
              items={row.items}
              direction={row.direction}
              duration={row.duration}
            />
          </div>
        ))}
      </div>
    </section>
  );
}
