// Animace inspirované cinematic landing page — BlurText, scroll reveal, motion stagger
// Vanilla impl bez framer-motion (přes IntersectionObserver + CSS transitions)

const { useEffect, useRef, useState } = React;

// ===== BlurText: word-by-word blur reveal =====
function BlurText({ text, className = "", delay = 0, stagger = 100, as = "span", style = {} }) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  const words = text.split(" ");

  useEffect(() => {
    if (!ref.current) return;
    // Fallback: if already in viewport at mount, trigger immediately
    const rect = ref.current.getBoundingClientRect();
    if (rect.top < window.innerHeight && rect.bottom > 0) {
      setVisible(true);
      return;
    }
    const obs = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) { setVisible(true); obs.disconnect(); }
      },
      { threshold: 0.1 }
    );
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);

  const Tag = as;
  return (
    <Tag ref={ref} className={`blur-text ${className}`} style={style}>
      {words.map((w, i) => (
        <span
          key={i}
          className={`blur-word ${visible ? "is-in" : ""}`}
          style={{ transitionDelay: `${delay + i * stagger}ms` }}
        >
          {w}
        </span>
      ))}
    </Tag>
  );
}

// ===== Reveal wrapper: fade+blur+slide on scroll =====
function Reveal({ children, delay = 0, y = 20, className = "", as = "div", once = true, id }) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    // Pokud je už ve viewportu při mountu (např. hero sekce), spusť animaci hned
    const rect = ref.current.getBoundingClientRect();
    if (rect.top < window.innerHeight * 0.95 && rect.bottom > 0) {
      const t = setTimeout(() => setVisible(true), 30);
      return () => clearTimeout(t);
    }
    const obs = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          if (once) obs.disconnect();
        } else if (!once) {
          setVisible(false);
        }
      },
      { threshold: 0.12, rootMargin: "0px 0px -60px 0px" }
    );
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [once]);
  const Tag = as;
  return (
    <Tag
      ref={ref}
      id={id}
      className={`reveal ${visible ? "is-in" : ""} ${className}`}
      style={{ transitionDelay: `${delay}ms`, "--reveal-y": `${y}px` }}
    >
      {children}
    </Tag>
  );
}

// ===== Stagger group: child .stagger-item appear in sequence =====
function StaggerGroup({ children, step = 80, delay = 0, className = "", once = true, contents = false, reverse = false }) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    // display:contents wrapper nemá layout box → observer/getBoundingClientRect
    // nefungují korektně. Pro contents=true použijeme první rendered dítě.
    const target = contents
      ? (ref.current.firstElementChild || ref.current)
      : ref.current;
    const rect = target.getBoundingClientRect();
    if (rect.top < window.innerHeight * 0.95 && rect.bottom > 0) {
      const t = setTimeout(() => setVisible(true), 30);
      return () => clearTimeout(t);
    }
    const obs = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          if (once) obs.disconnect();
        }
      },
      { threshold: 0.1, rootMargin: "0px 0px -60px 0px" }
    );
    obs.observe(target);
    return () => obs.disconnect();
  }, [once, contents]);

  const arr = React.Children.toArray(children);
  const N = arr.length;
  return (
    <div ref={ref} className={`stagger ${visible ? "is-in" : ""} ${className}`} style={contents ? { display: "contents" } : undefined}>
      {arr.map((child, i) => {
        const order = reverse ? (N - 1 - i) : i;
        return React.cloneElement(child, {
          style: {
            ...(child.props.style || {}),
            transitionDelay: `${delay + order * step}ms`,
          },
          className: `stagger-item ${child.props.className || ""}`,
        });
      })}
    </div>
  );
}

// ===== RevealSlide: cinematic slide-in z libovolného směru (left/right/up/down) =====
function RevealSlide({ children, delay = 0, dir = "left", distance = 120, rotate = 0, className = "", as = "div", once = true, id }) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    if (rect.top < window.innerHeight * 0.95 && rect.bottom > 0) {
      const t = setTimeout(() => setVisible(true), 30);
      return () => clearTimeout(t);
    }
    const obs = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setVisible(true);
          if (once) obs.disconnect();
        }
      },
      { threshold: 0.15, rootMargin: "0px 0px -80px 0px" }
    );
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [once]);
  const Tag = as;
  let x = 0, y = 0;
  if (dir === "right") x = distance;
  else if (dir === "left") x = -distance;
  else if (dir === "up") y = distance;
  else if (dir === "down") y = -distance;
  return (
    <Tag
      ref={ref}
      id={id}
      className={`reveal-slide ${visible ? "is-in" : ""} ${className}`}
      style={{
        transitionDelay: `${delay}ms`,
        "--slide-x": `${x}px`,
        "--slide-y": `${y}px`,
        "--slide-rot": `${rotate}deg`
      }}
    >
      {children}
    </Tag>
  );
}

window.BlurText = BlurText;
window.Reveal = Reveal;
window.StaggerGroup = StaggerGroup;
window.RevealSlide = RevealSlide;
