"use client";

import { useEffect, useRef, useState, type ReactNode } from "react";
import { useReducedMotion } from "framer-motion";
import { MagneticLink } from "@/components/motion/MagneticLink";

type Band = {
  kicker: string;
  headline: string;
  sub?: string;
  align: "left" | "right" | "center";
  range: [number, number];
  ramp?: number;
  actions?: ReactNode;
};

type Props = {
  heroImage: string;
  badge: string;
  brandName: string;
  lead: string;
  ctaPrimary: string;
  ctaPrimaryHref: string;
  ctaSecondary: string;
  ctaSecondaryHref: string;
};

/** Solo móvil pequeño y reduced-motion desactivan el scroll cinematográfico */
const SCRUB_OFF_GATES = [
  "(max-width: 640px)",
  "(prefers-reduced-motion: reduce)",
];

function smoothstep(p: number, e0: number, e1: number) {
  const t = Math.min(1, Math.max(0, (p - e0) / (e1 - e0)));
  return t * t * (3 - 2 * t);
}

function clamp(v: number, lo: number, hi: number) {
  return Math.min(hi, Math.max(lo, v));
}

function rng(seed: number) {
  let s = seed >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296;
}

function SplitHeadline({ text, seed }: { text: string; seed: number }) {
  const rand = rng(seed);
  const words = text.split(/\s+/);
  return (
    <span aria-hidden="true">
      {words.map((word, wi) => (
        <span key={wi} className="cine-w">
          {word.split("").map((ch, ci) => (
            <span
              key={ci}
              className="cine-c"
              style={
                {
                  ["--th" as string]: String(rand() * 0.5),
                  ["--jx" as string]: `${(rand() - 0.5) * 36}px`,
                  ["--jy" as string]: `${(rand() - 0.5) * 24}px`,
                  ["--jr" as string]: `${(rand() - 0.5) * 10}deg`,
                } as React.CSSProperties
              }
            >
              {ch}
            </span>
          ))}
        </span>
      ))}
    </span>
  );
}

function HeroParticles() {
  const items = Array.from({ length: 24 }, (_, i) => ({
    id: i,
    left: `${rng(i * 17)() * 100}%`,
    top: `${rng(i * 31)() * 100}%`,
    delay: `${rng(i * 11)() * 5}s`,
    dur: `${5 + rng(i * 23)() * 4}s`,
    size: 2 + rng(i * 7)() * 3,
  }));

  return (
    <div className="cine-particles" aria-hidden="true">
      {items.map((p) => (
        <span
          key={p.id}
          className="cine-particle"
          style={{
            left: p.left,
            top: p.top,
            width: p.size,
            height: p.size,
            animationDelay: p.delay,
            animationDuration: p.dur,
          }}
        />
      ))}
    </div>
  );
}

export function CinematicHero({
  heroImage,
  badge,
  brandName,
  lead,
  ctaPrimary,
  ctaPrimaryHref,
  ctaSecondary,
  ctaSecondaryHref,
}: Props) {
  const reduce = useReducedMotion();
  const pinRef = useRef<HTMLDivElement>(null);
  const stageRef = useRef<HTMLDivElement>(null);
  const mediaRef = useRef<HTMLDivElement>(null);
  const bandRefs = useRef<(HTMLDivElement | null)[]>([]);

  const [scrubOn, setScrubOn] = useState(false);
  const [staticSlide, setStaticSlide] = useState(0);
  const scrubOnRef = useRef(false);
  const targetRef = useRef(0);
  const shownRef = useRef(0);
  const rafRef = useRef<number | null>(null);
  const lastTickRef = useRef(0);
  const loadKRef = useRef(0);
  const loadStartRef = useRef<number | null>(null);
  const heroOnScreenRef = useRef(true);

  const staticSlides = [
    { kicker: badge, headline: brandName, sub: lead },
    {
      kicker: "Plataforma",
      headline: "Todo en un solo lugar",
      sub: "Servicios, clasificados y empleos para Puerto Rico.",
    },
  ];

  const bands: Band[] = [
    {
      kicker: badge,
      headline: brandName,
      sub: lead,
      align: "left",
      range: [0.04, 0.38],
      ramp: 0.05,
    },
    {
      kicker: "Plataforma",
      headline: "Servicios, clasificados y empleos",
      sub: "Un clic y entras a cada modulo.",
      align: "center",
      range: [0.55, 0.88],
      ramp: 0.04,
      actions: (
        <div className="cine-band__actions">
          <MagneticLink href={ctaPrimaryHref} className="btn-split">
            <span className="btn-split__label">{ctaPrimary}</span>
            <span className="btn-split__icon">→</span>
          </MagneticLink>
          <MagneticLink href={ctaSecondaryHref} className="btn-ghost">
            {ctaSecondary}
          </MagneticLink>
        </div>
      ),
    },
  ];

  function heroProgress() {
    const pin = pinRef.current;
    if (!pin) return 0;
    const rect = pin.getBoundingClientRect();
    const range = rect.height - window.innerHeight;
    if (range <= 0) return 0;
    return clamp(-rect.top / range, 0, 1);
  }

  function updateBand(
    el: HTMLDivElement,
    p: number,
    a: number,
    b: number,
    ramp: number,
    isFirst: boolean
  ) {
    const f = Math.min(0.02, (b - a) / 3);
    let opacity = smoothstep(p, a, a + f) * (1 - smoothstep(p, b - f, b));
    if (isFirst && p <= a + f) opacity = 1;

    const rampVal = ramp || Math.min(0.025, (b - a) * 0.35);
    let scrollK = clamp((p - a) / rampVal, 0, 1);
    if (isFirst) scrollK = Math.max(scrollK, loadKRef.current);

    const op = el.dataset.op;
    if (op !== String(opacity)) {
      el.style.opacity = String(opacity);
      el.dataset.op = String(opacity);
    }
    const k = el.dataset.k;
    const kStr = String(scrollK);
    if (k !== kStr && Math.abs(parseFloat(k || "0") - scrollK) > 0.008) {
      el.style.setProperty("--k", kStr);
      el.dataset.k = kStr;
    }
  }

  function tick(now: number) {
    const dt = Math.min(100, now - (lastTickRef.current || now));
    lastTickRef.current = now;
    const k = 0.16;
    shownRef.current +=
      (targetRef.current - shownRef.current) *
      (1 - Math.pow(1 - k, dt / 16.667));

    if (Math.abs(targetRef.current - shownRef.current) < 0.0005) {
      shownRef.current = targetRef.current;
      rafRef.current = null;
      lastTickRef.current = 0;
    } else {
      rafRef.current = requestAnimationFrame(tick);
    }

    if (loadStartRef.current === null) loadStartRef.current = now;
    if (loadKRef.current < 1) {
      const t = Math.min(1, (now - loadStartRef.current) / 1200);
      loadKRef.current = smoothstep(t, 0, 1);
    }

    const p = shownRef.current;
    const scale = 1 + p * 0.16;
    const y = p * -8;
    const hx = stageRef.current?.style.getPropertyValue("--hx") || "0px";
    const hy = stageRef.current?.style.getPropertyValue("--hy") || "0px";
    if (mediaRef.current) {
      mediaRef.current.style.transform = `scale(${scale}) translate3d(calc(${hx} * -0.15), calc(${y}% + ${hy} * -0.1), 0)`;
    }

    bandRefs.current.forEach((el, i) => {
      if (!el) return;
      const band = bands[i];
      updateBand(el, p, band.range[0], band.range[1], band.ramp ?? 0, i === 0);
    });
  }

  function onScroll() {
    targetRef.current = heroProgress();
    if (rafRef.current === null && heroOnScreenRef.current && scrubOnRef.current) {
      rafRef.current = requestAnimationFrame(tick);
    }
  }

  function enableScrub() {
    if (scrubOnRef.current) return;
    scrubOnRef.current = true;
    setScrubOn(true);
    stageRef.current?.classList.remove("cine-stage--static");
    window.addEventListener("scroll", onScroll, { passive: true });
    bandRefs.current.forEach((el) => {
      if (el) {
        delete el.dataset.op;
        delete el.dataset.k;
      }
    });
    onScroll();
  }

  function disableScrub() {
    if (!scrubOnRef.current) return;
    scrubOnRef.current = false;
    setScrubOn(false);
    stageRef.current?.classList.add("cine-stage--static");
    window.removeEventListener("scroll", onScroll);
    if (rafRef.current !== null) {
      cancelAnimationFrame(rafRef.current);
      rafRef.current = null;
    }
    bandRefs.current.forEach((el) => {
      if (!el) return;
      el.style.opacity = "1";
      el.style.setProperty("--k", "1");
    });
  }

  function applyHeroMode() {
    if (SCRUB_OFF_GATES.some((q) => window.matchMedia(q).matches)) disableScrub();
    else enableScrub();
  }

  function onPointerMove(e: React.PointerEvent) {
    if (!stageRef.current || reduce) return;
    const r = stageRef.current.getBoundingClientRect();
    const x = (e.clientX - r.left) / r.width - 0.5;
    const y = (e.clientY - r.top) / r.height - 0.5;
    stageRef.current.style.setProperty("--hx", `${x * 48}px`);
    stageRef.current.style.setProperty("--hy", `${y * 32}px`);
  }

  function onPointerLeave() {
    stageRef.current?.style.setProperty("--hx", "0px");
    stageRef.current?.style.setProperty("--hy", "0px");
  }

  useEffect(() => {
    if (reduce) {
      disableScrub();
      return;
    }
    const mqls = SCRUB_OFF_GATES.map((q) => window.matchMedia(q));
    mqls.forEach((m) => m.addEventListener("change", applyHeroMode));
    applyHeroMode();

    const pin = pinRef.current;
    if (!pin) return () => mqls.forEach((m) => m.removeEventListener("change", applyHeroMode));

    const io = new IntersectionObserver(
      (entries) => {
        heroOnScreenRef.current = entries[0]?.isIntersecting ?? true;
        if (!heroOnScreenRef.current && rafRef.current !== null) {
          cancelAnimationFrame(rafRef.current);
          rafRef.current = null;
        }
      },
      { threshold: 0 }
    );
    io.observe(pin);

    return () => {
      mqls.forEach((m) => m.removeEventListener("change", applyHeroMode));
      window.removeEventListener("scroll", onScroll);
      if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
      io.disconnect();
    };
  }, [reduce]);

  useEffect(() => {
    if (!reduce && scrubOn) return;
    const id = window.setInterval(() => {
      setStaticSlide((s) => (s + 1) % staticSlides.length);
    }, 4500);
    return () => clearInterval(id);
  }, [reduce, scrubOn, staticSlides.length]);

  const staticMode = reduce || !scrubOn;
  const slide = staticSlides[staticSlide];

  return (
    <div
      ref={pinRef}
      className={`cine-pin${staticMode ? " cine-pin--static" : ""}`}
      aria-label="Introduccion"
    >
      <div
        ref={stageRef}
        className={`cine-stage hero-stage${staticMode ? " cine-stage--static" : ""}`}
        onPointerMove={onPointerMove}
        onPointerLeave={onPointerLeave}
      >
        <section className="hero-bleed cine-bleed">
          <div
            ref={mediaRef}
            className="hero-bleed__media cine-bleed__media"
            style={{ backgroundImage: `url('${heroImage}')` }}
          />
          <div className="hero-bleed__veil" />
          <div className="hero-bleed__grid" aria-hidden="true" />
          <div className="hero-bleed__orb hero-bleed__orb--a" aria-hidden="true" />
          <div className="hero-bleed__orb hero-bleed__orb--b" aria-hidden="true" />
          <div className="hero-bleed__orb hero-bleed__orb--c" aria-hidden="true" />
          <div className="hero-bleed__scan" aria-hidden="true" />
          <div className="hero-bleed__noise" aria-hidden="true" />
          <div className="cine-scrim" aria-hidden="true" />
          <HeroParticles />
          <div className="cine-beam" aria-hidden="true" />
        </section>

        {staticMode ? (
          <div className="cine-settle">
            <span className="badge">
              <span className="hero-bleed__pulse" />
              {slide.kicker}
            </span>
            <h2 key={staticSlide} className="cine-settle__headline mt-4 text-3xl font-semibold sm:text-4xl">
              {slide.headline}
            </h2>
            {slide.sub ? (
              <p key={`sub-${staticSlide}`} className="cine-settle__sub mt-3 max-w-xl text-lg text-white/75">
                {slide.sub}
              </p>
            ) : null}
            <div className="cine-settle__dots" aria-hidden="true">
              {staticSlides.map((_, i) => (
                <span
                  key={i}
                  className={`cine-settle__dot${i === staticSlide ? " is-active" : ""}`}
                />
              ))}
            </div>
            <div className="mt-6 flex flex-wrap justify-center gap-3">
              <MagneticLink href={ctaPrimaryHref} className="btn-split">
                <span className="btn-split__label">{ctaPrimary}</span>
                <span className="btn-split__icon">→</span>
              </MagneticLink>
              <MagneticLink href={ctaSecondaryHref} className="btn-ghost">
                {ctaSecondary}
              </MagneticLink>
            </div>
          </div>
        ) : (
          <div className="cine-bands">
            {bands.map((band, i) => (
              <div
                key={i}
                ref={(el) => {
                  bandRefs.current[i] = el;
                }}
                className={`cine-band cine-band--${band.align}`}
                data-band={`${band.range[0]},${band.range[1]}`}
              >
                <p className="cine-band__kicker">{band.kicker}</p>
                <h1 className="cine-band__headline">
                  <span className="sr-only">{band.headline}</span>
                  <SplitHeadline text={band.headline} seed={i * 7919 + 1} />
                </h1>
                {band.sub ? <p className="cine-band__sub">{band.sub}</p> : null}
                {band.actions}
              </div>
            ))}
          </div>
        )}

        {!staticMode ? (
          <p className="cine-scroll-cue" aria-hidden="true">
            Desliza para explorar
          </p>
        ) : null}
      </div>
    </div>
  );
}
