// Testimonials.jsx — rotated pastel proof cards.
function ProofCard({ quote, name, role, company, tone, tilt, stagger }) {
  return (
    <figure
      className={`zg-proof-card zg-proof-card--${tone} zg-proof-card--${tilt}${stagger ? " zg-proof-card--stagger" : ""}`}
    >
      <blockquote className="zg-proof-quote">{quote}</blockquote>
      <figcaption className="zg-proof-byline">
        <span className="zg-proof-avatar" aria-hidden="true">
          {name.charAt(0)}
        </span>
        <span className="zg-proof-meta">
          <span className="zg-proof-name">{name}</span>
          <span className="zg-proof-role">
            {role} · {company}
          </span>
        </span>
      </figcaption>
      <span className="zg-proof-mono" aria-hidden="true">
        Z
      </span>
    </figure>
  );
}

const PROOF_CARD_MOTION = [
  { startRot: -12, endRot: -3, startY: 56 },
  { startRot: 15, endRot: 4, startY: 72 },
  { startRot: -10, endRot: -3, startY: 56 },
];

function Testimonials() {
  const sectionRef = React.useRef(null);
  const playedRef = React.useRef(false);

  const quotes = [
    {
      quote: "We stopped correcting payroll files the night before they went out.",
      name: "D.R.",
      role: "Director of Operations",
      company: "Anesthesia management group",
      tone: "blush",
      tilt: "left",
    },
    {
      quote:
        "I can find an answer in the files now. Before, I was just hoping someone remembered.",
      name: "K.M.",
      role: "Principal",
      company: "Executive compensation consultancy",
      tone: "sage",
      tilt: "right",
      stagger: true,
    },
    {
      quote: "Our clients can see their own results now. That changed the conversation.",
      name: "T.B.",
      role: "Head of Client Success",
      company: "Payment optimization firm",
      tone: "lilac",
      tilt: "left",
    },
  ];

  React.useEffect(() => {
    const section = sectionRef.current;
    if (!section) return undefined;

    const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const mobile = window.matchMedia("(max-width: 900px)").matches;
    const gsap = window.gsap;

    const clearCardMotion = (cards) => {
      if (!gsap) return;
      cards.forEach((card) => {
        gsap.set(card, { clearProps: "transform,opacity" });
        card.querySelectorAll(".zg-proof-mono, .zg-proof-quote, .zg-proof-byline").forEach((el) => {
          gsap.set(el, { clearProps: "all" });
        });
      });
    };

    const play = () => {
      if (playedRef.current) return;
      playedRef.current = true;

      const opener = section.querySelector(".zg-proof-opener");
      const label = section.querySelector(".zg-proof-opener .label");
      const title = section.querySelector(".zg-proof-opener h2");
      const cards = section.querySelectorAll(".zg-proof-card");

      if (reduced || !gsap) {
        section.classList.add("zg-proof-section--revealed");
        return;
      }

      const tl = gsap.timeline({ defaults: { ease: "power3.out" } });

      tl.from(opener, { opacity: 0, y: 28, duration: 0.7 })
        .from(label, { opacity: 0, y: 14, duration: 0.55 }, "-=0.55")
        .from(title, { opacity: 0, y: 24, duration: 0.75 }, "-=0.45");

      cards.forEach((card, index) => {
        const motion = PROOF_CARD_MOTION[index] || PROOF_CARD_MOTION[0];
        const mono = card.querySelector(".zg-proof-mono");
        const quote = card.querySelector(".zg-proof-quote");
        const byline = card.querySelector(".zg-proof-byline");
        const position = index === 0 ? "-=0.1" : "-=0.42";

        if (mobile) {
          tl.fromTo(
            card,
            { opacity: 0, y: 40 },
            { opacity: 1, y: 0, duration: 0.65 },
            position
          );
        } else {
          tl.fromTo(
            card,
            {
              opacity: 0,
              y: motion.startY,
              rotation: motion.startRot,
              scale: 0.94,
              transformOrigin: "50% 82%",
            },
            {
              opacity: 1,
              y: 0,
              rotation: motion.endRot,
              scale: 1,
              duration: 0.88,
              transformOrigin: "50% 82%",
            },
            position
          );
        }

        if (mono) {
          tl.fromTo(
            mono,
            { opacity: 0, scale: 0.78, y: 12 },
            { opacity: 0.1, scale: 1, y: 0, duration: 0.7, ease: "power2.out" },
            "<0.18"
          );
        }

        if (quote) {
          tl.fromTo(quote, { opacity: 0, y: 16 }, { opacity: 1, y: 0, duration: 0.55 }, "<0.1");
        }

        if (byline) {
          tl.fromTo(
            byline,
            { opacity: 0, x: -14 },
            { opacity: 1, x: 0, duration: 0.5 },
            "<0.06"
          );
        }
      });

      tl.add(() => {
        section.classList.add("zg-proof-section--revealed");
        clearCardMotion(cards);
      });
    };

    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          play();
          io.disconnect();
        }
      },
      { threshold: 0.2 }
    );

    io.observe(section);

    let cleanupTilts = () => {};
    if (!reduced && window.matchMedia("(hover: hover)").matches) {
      const cards = section.querySelectorAll(".zg-proof-card");
      const cleanups = [];

      cards.forEach((card) => {
        let raf = 0;
        let targetX = 0;
        let targetY = 0;
        let currentX = 0;
        let currentY = 0;
        let active = false;

        const paint = () => {
          raf = 0;
          currentX += (targetX - currentX) * 0.15;
          currentY += (targetY - currentY) * 0.15;
          card.style.setProperty("--tilt-x", `${currentX.toFixed(2)}deg`);
          card.style.setProperty("--tilt-y", `${currentY.toFixed(2)}deg`);
          if (
            active ||
            Math.abs(currentX - targetX) > 0.05 ||
            Math.abs(currentY - targetY) > 0.05
          ) {
            raf = requestAnimationFrame(paint);
          }
        };

        const queue = () => {
          if (!raf) raf = requestAnimationFrame(paint);
        };

        const onMove = (event) => {
          const rect = card.getBoundingClientRect();
          const nx = (event.clientX - rect.left) / rect.width;
          const ny = (event.clientY - rect.top) / rect.height;
          const tiltMax = 5;
          targetY = (nx - 0.5) * tiltMax * 2;
          targetX = (0.5 - ny) * tiltMax * 2;
          active = true;
          queue();
        };

        const onLeave = () => {
          targetX = 0;
          targetY = 0;
          active = false;
          queue();
        };

        card.addEventListener("pointermove", onMove);
        card.addEventListener("pointerleave", onLeave);

        cleanups.push(() => {
          card.removeEventListener("pointermove", onMove);
          card.removeEventListener("pointerleave", onLeave);
          if (raf) cancelAnimationFrame(raf);
        });
      });

      cleanupTilts = () => cleanups.forEach((fn) => fn());
    }

    return () => {
      io.disconnect();
      cleanupTilts();
    };
  }, []);

  return (
    <section
      ref={sectionRef}
      className="zg-proof-section"
      aria-labelledby="zg-proof-title"
    >
      <div className="zg-container">
        <header className="zg-proof-header">
          <div className="zg-proof-opener">
            <span className="label">What clients say</span>
            <h2 id="zg-proof-title">
              Outcomes, <span className="zg-highlight">not applause</span>.
              <span className="muted">From the teams we built for.</span>
            </h2>
          </div>
        </header>

        <div className="zg-proof-grid">
          {quotes.map((item) => (
            <ProofCard key={item.name} {...item} />
          ))}
        </div>
      </div>
    </section>
  );
}

window.Testimonials = Testimonials;
