// Reusable primitives: FadeIn, Magnet, ContactButton, LiveProjectButton, AnimatedText
const { motion, useScroll, useTransform, useMotionValue, useSpring } = window.FramerMotion || window.Motion || {};
// Framer Motion UMD exposes as window.Motion or window.FramerMotion depending on version.
const FM = window.Motion || window.FramerMotion;
const _motion = FM.motion;
const _useScroll = FM.useScroll;
const _useTransform = FM.useTransform;

/* ---------- FadeIn ---------- */
function FadeIn({ as = "div", children, delay = 0, duration = 0.7, x = 0, y = 30, className, style, ...rest }) {
  const Tag = (as && _motion[as]) ? _motion[as] : _motion.div;
  return (
    <Tag
      initial={{ opacity: 0, x, y }}
      whileInView={{ opacity: 1, x: 0, y: 0 }}
      viewport={{ once: true, margin: "50px", amount: 0 }}
      transition={{ duration, delay, ease: "easeOut" }}
      className={className}
      style={style}
      {...rest}
    >
      {children}
    </Tag>
  );
}

/* ---------- Magnet ---------- */
function Magnet({
  children,
  padding = 150,
  strength = 3,
  activeTransition = "transform 0.3s ease-out",
  inactiveTransition = "transform 0.6s ease-in-out",
  className,
  style,
}) {
  const ref = React.useRef(null);
  const [active, setActive] = React.useState(false);
  const [pos, setPos] = React.useState({ x: 0, y: 0 });

  React.useEffect(() => {
    const handleMove = (e) => {
      const el = ref.current;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      const cx = rect.left + rect.width / 2;
      const cy = rect.top + rect.height / 2;
      const dx = e.clientX - cx;
      const dy = e.clientY - cy;
      const within =
        Math.abs(dx) < rect.width / 2 + padding &&
        Math.abs(dy) < rect.height / 2 + padding;
      if (within) {
        setActive(true);
        setPos({ x: dx / strength, y: dy / strength });
      } else {
        setActive(false);
        setPos({ x: 0, y: 0 });
      }
    };
    window.addEventListener("mousemove", handleMove);
    return () => window.removeEventListener("mousemove", handleMove);
  }, [padding, strength]);

  return (
    <div
      ref={ref}
      className={className}
      style={{
        ...style,
        transform: `translate3d(${pos.x}px, ${pos.y}px, 0)`,
        transition: active ? activeTransition : inactiveTransition,
        willChange: "transform",
      }}
    >
      {children}
    </div>
  );
}

/* ---------- ContactButton ---------- */
function ContactButton({ className = "" }) {
  return (
    <button
      className={
        "contact-btn rounded-full text-white font-medium uppercase tracking-widest " +
        "px-8 py-3 sm:px-10 sm:py-3.5 md:px-12 md:py-4 " +
        "text-xs sm:text-sm md:text-base " +
        "transition-transform duration-200 hover:scale-[1.03] active:scale-[0.98] " +
        className
      }
    >
      Contact Me
    </button>
  );
}

/* ---------- LiveProjectButton ---------- */
function LiveProjectButton({ className = "", onClick }) {
  const handleClick = onClick || (() => { window.location.href = 'projects.html'; });
  return (
    <button
      onClick={handleClick}
      className={
        "rounded-full border-2 border-[#D7E2EA] text-[#D7E2EA] font-medium uppercase tracking-widest " +
        "px-4 py-2 sm:px-8 sm:py-3 " +
        "text-xs sm:text-sm " +
        "transition-colors duration-200 hover:bg-[#D7E2EA]/10 cursor-pointer " +
        className
      }
    >
      View Project
    </button>
  );
}

/* ---------- AnimatedText (char-by-char scroll reveal) ---------- */
function AnimatedText({ text, className, style }) {
  const ref = React.useRef(null);
  const { scrollYProgress } = _useScroll({
    target: ref,
    offset: ["start 0.8", "end 0.2"],
  });

  const words = React.useMemo(() => {
    const total = text.length;
    return text.split(" ").map((word, wi, arr) => {
      const offset = arr.slice(0, wi).reduce((acc, w) => acc + w.length + 1, 0);
      return { word, offset, total };
    });
  }, [text]);

  return (
    <p ref={ref} className={className} style={{ ...style, wordBreak: "normal", hyphens: "none" }}>
      {words.map(({ word, offset, total }, wi) => (
        <span key={wi} style={{ display: "inline-block", whiteSpace: "nowrap" }}>
          {word.split("").map((ch, ci) => (
            <Char key={ci} progress={scrollYProgress} index={offset + ci} total={total}>
              {ch}
            </Char>
          ))}
          {wi < words.length - 1 && <span style={{ display: "inline-block", width: "0.3em" }} />}
        </span>
      ))}
    </p>
  );
}

function Char({ children, progress, index, total }) {
  const coverage = 0.6;
  const start = (index / total) * coverage;
  const end = start + (1 / total) * coverage;
  const opacity = _useTransform(progress, [start, end], [0.2, 1]);
  return (
    <span style={{ position: "relative", display: "inline-block" }}>
      <span style={{ opacity: 0 }}>{children}</span>
      <_motion.span style={{ opacity, position: "absolute", left: 0, top: 0 }}>
        {children}
      </_motion.span>
    </span>
  );
}

/* ---------- useIsMobile hook ---------- */
function useIsMobile(breakpoint = 640) {
  const [isMobile, setIsMobile] = React.useState(window.innerWidth < breakpoint);
  React.useEffect(() => {
    const fn = () => setIsMobile(window.innerWidth < breakpoint);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, [breakpoint]);
  return isMobile;
}

Object.assign(window, {
  FadeIn, Magnet, ContactButton, LiveProjectButton, AnimatedText,
  useIsMobile,
  _motion, _useScroll, _useTransform, FM,
});
