"use client";

import {
  useEffect,
  useRef,
  useState,
  useSyncExternalStore,
  type TransitionEvent,
} from "react";
import { Quote } from "lucide-react";
import { appReviews } from "@/lib/home-content";
import ScrollReveal from "@/components/ScrollReveal";
import SectionBackdrop from "@/components/ui/SectionBackdrop";
import SectionHeader, { Highlight } from "@/components/ui/SectionHeader";

const AUTO_MS = 2800;
const SLIDE_MS = 800;

function subscribeQueries(queries: string[]) {
  return (onChange: () => void) => {
    const mqs = queries.map((q) => window.matchMedia(q));
    mqs.forEach((m) => m.addEventListener("change", onChange));
    return () => mqs.forEach((m) => m.removeEventListener("change", onChange));
  };
}

const PER_VIEW_QUERIES = ["(min-width: 1024px)", "(min-width: 640px)"];
const subscribePerView = subscribeQueries(PER_VIEW_QUERIES);
const subscribeReduce = subscribeQueries(["(prefers-reduced-motion: reduce)"]);

/** Reviews per view: 3 on desktop (one line), 2 on tablet, 1 on mobile. */
function usePerView() {
  return useSyncExternalStore(
    subscribePerView,
    () =>
      window.matchMedia(PER_VIEW_QUERIES[0]).matches
        ? 3
        : window.matchMedia(PER_VIEW_QUERIES[1]).matches
          ? 2
          : 1,
    () => 1,
  );
}

function usePrefersReducedMotion() {
  return useSyncExternalStore(
    subscribeReduce,
    () => window.matchMedia("(prefers-reduced-motion: reduce)").matches,
    () => false,
  );
}

/** Reviews — several cards per view, sliding one card at a time in a seamless loop. Pauses on hover/focus. No manual controls. */
export default function Reviews() {
  const count = appReviews.length;
  const perView = usePerView();
  const [index, setIndex] = useState(0);
  const [animate, setAnimate] = useState(true);
  const [paused, setPaused] = useState(false);
  const reduceMotion = usePrefersReducedMotion();
  const wrapped = useRef(false);

  // Slide only when there are more reviews than fit, and motion is allowed; otherwise show a static grid.
  const canSlide = count > perView && !reduceMotion;
  // The first `perView` cards are cloned after the last one so the loop never jumps.
  const clones = canSlide ? appReviews.slice(0, perView) : [];
  const realIndex = index % Math.max(count, 1);

  // Restart from the beginning whenever the layout changes (state adjusted during render, not in an effect).
  const layoutKey = `${perView}-${canSlide}`;
  const [prevLayoutKey, setPrevLayoutKey] = useState(layoutKey);
  if (prevLayoutKey !== layoutKey) {
    setPrevLayoutKey(layoutKey);
    setAnimate(false);
    setIndex(0);
  }

  // After a snap-back (transition disabled), re-enable the transition once the jump has painted.
  useEffect(() => {
    if (animate) return;
    const id = setTimeout(() => setAnimate(true), 60);
    return () => clearTimeout(id);
  }, [animate]);

  // Autoplay: advance one card at a time.
  useEffect(() => {
    if (paused || !canSlide || !animate) return;
    // The loop position already dwelled during the slide into the clones, so shorten the wait after a snap-back.
    const delay = wrapped.current ? AUTO_MS - SLIDE_MS : AUTO_MS;
    wrapped.current = false;
    const id = setTimeout(() => setIndex((i) => i + 1), delay);
    return () => clearTimeout(id);
  }, [index, paused, canSlide, animate]);

  // Reached the cloned tail: jump back to the identical start position without animating.
  function snapToStart() {
    wrapped.current = true;
    setAnimate(false);
    setIndex(0);
  }
  function handleTransitionEnd(e: TransitionEvent<HTMLDivElement>) {
    if (e.target !== e.currentTarget) return;
    if (index >= count) snapToStart();
  }
  // Fallback if transitionend never fires (e.g. background tab): still snap back once the slide should be done.
  useEffect(() => {
    if (!canSlide || index < count) return;
    const id = setTimeout(snapToStart, SLIDE_MS + 150);
    return () => clearTimeout(id);
  }, [index, canSlide, count]);

  if (count === 0) return null;

  return (
    <section
      id="reviews"
      className="relative scroll-mt-24 overflow-x-clip py-20 sm:py-24 lg:py-28"
    >
      <SectionBackdrop variant="radial" />

      <div className="container">
        <SectionHeader
          eyebrow="Reviews"
          title={
            <>
              What People Say <Highlight>About Our Apps</Highlight>
            </>
          }
          description="Real feedback from people who use our applications."
        />

        <ScrollReveal delay={120} variant="scale" className="mx-auto mt-14">
          <div
            role="region"
            aria-roledescription="carousel"
            aria-label="Reviews"
            tabIndex={0}
            onMouseEnter={() => setPaused(true)}
            onMouseLeave={() => setPaused(false)}
            onFocus={() => setPaused(true)}
            onBlur={() => setPaused(false)}
            className="rounded-[2rem] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-4"
          >
            <div className={`-mx-3 ${canSlide ? "overflow-hidden" : ""}`}>
              <div
                className={`flex ${canSlide ? "" : "flex-wrap"} ${
                  canSlide && animate
                    ? "transition-transform duration-800 ease-in-out"
                    : ""
                }`}
                style={
                  canSlide
                    ? { transform: `translateX(-${index * (100 / perView)}%)` }
                    : undefined
                }
                onTransitionEnd={handleTransitionEnd}
                aria-live={paused || !canSlide ? "polite" : "off"}
              >
                {[...appReviews, ...clones].map((r, i) => {
                  const isClone = i >= count;
                  const visible =
                    !canSlide ||
                    (!isClone && i >= realIndex && i < realIndex + perView);
                  return (
                    <div
                      key={`${r.appName}-${r.reviewerName}-${isClone ? "clone" : "item"}`}
                      role="group"
                      aria-roledescription="slide"
                      aria-label={`${(i % count) + 1} of ${count}`}
                      aria-hidden={!visible}
                      inert={!visible}
                      className="min-w-0 shrink-0 px-3 py-4"
                      style={{ flexBasis: `${100 / perView}%` }}
                    >
                      <figure className="relative m-0 flex h-full flex-col overflow-hidden rounded-3xl border border-slate-200 bg-white p-6 shadow-card sm:p-7">
                        <Quote
                          aria-hidden
                          strokeWidth={1.25}
                          className="pointer-events-none absolute right-4 top-4 h-16 w-16 text-accent/9"
                        />
                        <p className="relative text-xs font-semibold uppercase tracking-[0.16em] text-accent-600">
                          {r.appName}
                        </p>
                        <blockquote className="relative mt-4 flex-1 wrap-break-word font-display text-lg font-medium leading-[1.6] tracking-tight text-[#0F172A]">
                          “{r.review}”
                        </blockquote>
                        <figcaption className="relative mt-6 border-t border-slate-200 pt-4 text-sm font-semibold text-ink-200">
                          — {r.reviewerName}
                        </figcaption>
                      </figure>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        </ScrollReveal>
      </div>
    </section>
  );
}
