// Karavi Studio · Shared motion primitives (framer-motion)
const { motion, AnimatePresence, useScroll, useTransform, useSpring, useInView, useMotionValue } = window.framerMotion;
const { useRef, useState, useEffect } = React;

/* ── Spring presets ─────────────────────────────── */
const springs = {
  soft:    { type: "spring", stiffness: 220, damping: 30, mass: 0.9 },
  pop:     { type: "spring", stiffness: 360, damping: 26, mass: 0.8 },
  drawer:  { type: "spring", stiffness: 300, damping: 32, mass: 0.85 },
  gentle:  { type: "spring", stiffness: 140, damping: 22, mass: 1 },
};

/* ── Variants ───────────────────────────────────── */
const variants = {
  fadeUp: {
    hidden: { opacity: 0, y: 24 },
    show:   { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.22, 0.61, 0.36, 1] } },
  },
  fadeIn: {
    hidden: { opacity: 0 },
    show:   { opacity: 1, transition: { duration: 0.7, ease: "easeOut" } },
  },
  scaleIn: {
    hidden: { opacity: 0, scale: 0.96 },
    show:   { opacity: 1, scale: 1, transition: { duration: 0.55, ease: [0.22, 0.61, 0.36, 1] } },
  },
  staggerParent: {
    hidden: { opacity: 1 },
    show: {
      opacity: 1,
      transition: { staggerChildren: 0.08, delayChildren: 0.05 },
    },
  },
  staggerChild: {
    hidden: { opacity: 0, y: 18 },
    show:   { opacity: 1, y: 0, transition: { duration: 0.55, ease: [0.22, 0.61, 0.36, 1] } },
  },
  pageEnter: {
    hidden: { opacity: 0, y: 12 },
    show:   { opacity: 1, y: 0, transition: { duration: 0.42, ease: [0.22, 0.61, 0.36, 1] } },
    exit:   { opacity: 0, y: -8, transition: { duration: 0.26, ease: "easeIn" } },
  },
};

/* ── Reveal: section fade-up on scroll ──────────── */
const Reveal = ({ children, delay = 0, y = 24, once = true, as: Tag = "div", style, ...rest }) => {
  const Component = motion[Tag] || motion.div;
  return (
    <Component
      initial={{ opacity: 0, y }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once, amount: 0.18 }}
      transition={{ duration: 0.6, delay, ease: [0.22, 0.61, 0.36, 1] }}
      style={style}
      {...rest}
    >
      {children}
    </Component>
  );
};

/* ── Stagger: parent + child wrappers ───────────── */
const Stagger = ({ children, delayChildren = 0.05, staggerChildren = 0.08, once = true, style, className, as = "div", ...rest }) => {
  const Component = motion[as] || motion.div;
  return (
    <Component
      initial="hidden"
      whileInView="show"
      viewport={{ once, amount: 0.12 }}
      variants={{
        hidden: { opacity: 1 },
        show:   { transition: { staggerChildren, delayChildren } },
      }}
      style={style}
      className={className}
      {...rest}
    >
      {children}
    </Component>
  );
};

const StaggerItem = ({ children, y = 18, style, className, as = "div", ...rest }) => {
  const Component = motion[as] || motion.div;
  return (
    <Component
      variants={{
        hidden: { opacity: 0, y },
        show:   { opacity: 1, y: 0, transition: { duration: 0.55, ease: [0.22, 0.61, 0.36, 1] } },
      }}
      style={style}
      className={className}
      {...rest}
    >
      {children}
    </Component>
  );
};

/* ── Page transition wrapper ────────────────────── */
const PageTransition = ({ pageKey, children }) => (
  <AnimatePresence mode="wait">
    <motion.div
      key={pageKey}
      initial={{ opacity: 0, y: 12 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -6 }}
      transition={{ duration: 0.34, ease: [0.22, 0.61, 0.36, 1] }}
    >
      {children}
    </motion.div>
  </AnimatePresence>
);

/* ── Marquee: horizontal infinite text ──────────── */
// Uses CSS animation for performance; passes through with mask gradient (defined in index.html)
const Marquee = ({ items, separator = "·" }) => {
  // duplicate items so the animation loop is seamless
  const doubled = [...items, ...items];
  return (
    <div className="k-marquee" aria-label={items.join(", ")}>
      <div className="k-marquee-track">
        {doubled.map((it, i) => (
          <span key={i} className="k-marquee-item" aria-hidden={i >= items.length}>
            <span>{it}</span>
            <span className="k-marquee-dot"/>
          </span>
        ))}
      </div>
    </div>
  );
};

/* ── Magnetic button: subtle cursor-follow on desktop ── */
const MagneticButton = ({ children, strength = 12, style, ...rest }) => {
  const ref = useRef(null);
  const x = useMotionValue(0);
  const y = useMotionValue(0);
  const sx = useSpring(x, { stiffness: 260, damping: 22, mass: 0.5 });
  const sy = useSpring(y, { stiffness: 260, damping: 22, mass: 0.5 });

  const onMove = (e) => {
    if (window.matchMedia("(pointer: coarse)").matches) return;
    const rect = ref.current?.getBoundingClientRect();
    if (!rect) return;
    const dx = e.clientX - (rect.left + rect.width / 2);
    const dy = e.clientY - (rect.top + rect.height / 2);
    x.set((dx / rect.width) * strength);
    y.set((dy / rect.height) * strength);
  };
  const onLeave = () => { x.set(0); y.set(0); };

  return (
    <motion.button
      ref={ref}
      onMouseMove={onMove}
      onMouseLeave={onLeave}
      style={{ x: sx, y: sy, ...style }}
      whileTap={{ scale: 0.97 }}
      {...rest}
    >
      {children}
    </motion.button>
  );
};

/* ── Animated counter: counts to value when in view ── */
const Counter = ({ to = 0, suffix = "", duration = 1.6, style }) => {
  const ref = useRef(null);
  const inView = useInView(ref, { once: true, amount: 0.6 });
  const [val, setVal] = useState(0);

  useEffect(() => {
    if (!inView) return;
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - start) / (duration * 1000));
      const eased = 1 - Math.pow(1 - t, 3);
      setVal(Math.round(eased * to));
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => raf && cancelAnimationFrame(raf);
  }, [inView, to, duration]);

  return <span ref={ref} style={style}>{val.toLocaleString("en-IN")}{suffix}</span>;
};

/* ── Parallax wrapper: bg moves slower than scroll ── */
const Parallax = ({ children, speed = 0.25, style, ...rest }) => {
  const ref = useRef(null);
  const { scrollYProgress } = useScroll({ target: ref, offset: ["start end", "end start"] });
  const y = useTransform(scrollYProgress, [0, 1], [`-${speed * 60}px`, `${speed * 60}px`]);
  return (
    <div ref={ref} style={{ overflow: "hidden", ...style }} {...rest}>
      <motion.div style={{ y, height: "100%" }}>{children}</motion.div>
    </div>
  );
};

Object.assign(window, {
  motion, AnimatePresence, useScroll, useTransform, useInView, useSpring, useMotionValue,
  springs, variants,
  Reveal, Stagger, StaggerItem, PageTransition, Marquee, MagneticButton, Counter, Parallax,
});
