// Botón de llamada a la acción gamificado — un compañero que salta
// a distintos lugares de la pantalla siguiendo tu lectura.
const { useState: useJState, useEffect: useJEffect, useRef: useJRef } = React;

const JOURNEY_FORM_URL = "https://form.typeform.com/to/vkeyUZXs";

// Perchas: posiciones por las que va saltando (fracciones del área libre)
const PERCHES = [
  { fx: 0.02, fy: 0.93 }, // abajo izquierda
  { fx: 0.60, fy: 0.90 }, // abajo centro
  { fx: 0.02, fy: 0.42 }, // borde izquierdo, a media altura
  { fx: 0.55, fy: 0.06 }, // arriba centro
  { fx: 0.03, fy: 0.07 }, // arriba izquierda
  { fx: 0.65, fy: 0.45 }, // centro derecha (junto al contenido)
];

const TAUNTS = [
  "¡Sígueme!",
  "¡Por aquí!",
  "¡Vas muy bien!",
  "¿Me alcanzas?",
  "El quiz te espera…",
  "¡Ya casi!",
  "¡Una más y listo!",
];

const HOP_COLORS = ["#d96e48", "#3e8e9b", "#7a8f3e", "#9b6ed9", "#d9a23e", "#c75e7f"];
const SETTLE_PERCH = { fx: 0.02, fy: 0.93 }; // reposo: abajo a la izquierda
const SETTLE_AFTER_MS = 3 * 60 * 1000; // 3 minutos

function JourneyButton({ chatOpen }) {
  const KEY = "ego-journey-v1";
  const [reached, setReached] = useJState(() => {
    try { return JSON.parse(localStorage.getItem(KEY)) || []; } catch (e) { return []; }
  });
  const [total, setTotal] = useJState(0);
  const [current, setCurrent] = useJState(0); // sección visible ahora
  const [started, setStarted] = useJState(() => reached.length > 0);
  const [pos, setPos] = useJState(null);
  const [hopping, setHopping] = useJState(false);
  const [bubble, setBubble] = useJState(null);
  const [settled, setSettled] = useJState(false); // por visita: cada carga vuelve a jugar
  const settledRef = useJRef(settled);
  const chatOpenRef = useJRef(chatOpen);
  const wrapRef = useJRef(null);
  const prevCurrent = useJRef(-1);
  const hopCount = useJRef(0);
  const bubbleTimer = useJRef(null);

  useJEffect(() => { localStorage.setItem(KEY, JSON.stringify(reached)); }, [reached]);

  // Se asienta tras 3 minutos, o al llegar al fondo (lo que ocurra primero)
  useJEffect(() => { settledRef.current = settled; }, [settled]);
  useJEffect(() => {
    const t = setTimeout(() => setSettled(true), SETTLE_AFTER_MS);
    return () => clearTimeout(t);
  }, []);

  // Observa el scroll: progreso acumulado + sección actual
  useJEffect(() => {
    const secs = Array.from(document.querySelectorAll("main .sec"));
    setTotal(secs.length);
    let ticking = false;
    const check = () => {
      ticking = false;
      const line = window.innerHeight * 0.6;
      let cur = 0;
      const newly = [];
      secs.forEach((el, i) => {
        if (el.getBoundingClientRect().top < line) { newly.push(i); cur = i + 1; }
      });
      setCurrent(cur);
      // ¿Llegamos al fondo de la página?
      const doc = document.documentElement;
      if (window.scrollY + window.innerHeight >= doc.scrollHeight - 80) setSettled(true);
      setReached((prev) => {
        const merged = Array.from(new Set([...prev, ...newly]));
        return merged.length === prev.length ? prev : merged;
      });
    };
    const onScroll = () => {
      if (!ticking) { ticking = true; requestAnimationFrame(check); }
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    check();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // Posición de la percha según la sección actual (esquiva chat y barra móvil)
  const computePos = (cur, isSettled) => {
    // Con el chat abierto en móvil, baja al fondo para no estorbar la conversación
    const mobileChat = chatOpenRef.current && window.innerWidth < 1024;
    const perch = (isSettled || mobileChat) ? SETTLE_PERCH : PERCHES[cur % PERCHES.length];
    const w = window.innerWidth, h = window.innerHeight;
    const btn = wrapRef.current;
    const bw = btn ? btn.offsetWidth : 215;
    const bh = btn ? btn.offsetHeight : 64;
    let availW = w;
    if (w >= 1024) {
      const chat = document.querySelector(".ego-panel");
      if (chat) availW = chat.getBoundingClientRect().left;
    }
    const minY = w < 1024 ? 82 : 14;
    const x = Math.max(14, Math.min(perch.fx * (availW - bw), availW - bw - 14));
    const y = Math.max(minY, Math.min(perch.fy * (h - bh), h - bh - 12));
    return { x, y };
  };

  // Salta de percha cada vez que cambias de sección (subiendo o bajando);
  // una vez asentado, se queda quieto abajo.
  useJEffect(() => {
    if (settled) {
      setPos(computePos(0, true));
      setHopping(false);
      return;
    }
    setPos(computePos(current, false));
    if (prevCurrent.current === -1) { prevCurrent.current = current; return; }
    if (current !== prevCurrent.current) {
      prevCurrent.current = current;
      hopCount.current += 1;
      setHopping(true);
      setBubble(TAUNTS[hopCount.current % TAUNTS.length]);
      clearTimeout(bubbleTimer.current);
      bubbleTimer.current = setTimeout(() => setBubble(null), 2600);
      const t = setTimeout(() => setHopping(false), 950);
      return () => clearTimeout(t);
    }
  }, [current, total, settled]);

  useJEffect(() => {
    const onResize = () => setPos(computePos(prevCurrent.current < 0 ? 0 : prevCurrent.current, settledRef.current));
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // Reposiciona al abrir/cerrar el chat en móvil
  useJEffect(() => {
    chatOpenRef.current = chatOpen;
    setPos(computePos(prevCurrent.current < 0 ? 0 : prevCurrent.current, settledRef.current));
    if (chatOpen && window.innerWidth < 1024) setBubble(null);
  }, [chatOpen]);

  const done = total > 0 && reached.length >= total;
  const pct = total > 0 ? reached.length / total : 0;

  useJEffect(() => {
    if (done) {
      setBubble("¡Lo lograste!");
      clearTimeout(bubbleTimer.current);
      bubbleTimer.current = setTimeout(() => setBubble(null), 3500);
    }
  }, [done]);

  const go = () => {
    if (!started) setStarted(true);
    if (done) {
      window.open(JOURNEY_FORM_URL, "_blank", "noopener");
      return;
    }
    const secs = Array.from(document.querySelectorAll("main .sec"));
    const nextIdx = secs.findIndex((_, i) => !reached.includes(i));
    const target = secs[nextIdx === -1 ? 0 : nextIdx];
    if (target) {
      const y = target.getBoundingClientRect().top + window.scrollY - 84;
      window.scrollTo({ top: y, behavior: "smooth" });
    }
  };

  const R = 15.5;
  const C = 2 * Math.PI * R;
  const label = done ? "Empezar ahora" : !started ? "Empezar" : "Continuar";
  const hopColor = HOP_COLORS[hopCount.current % HOP_COLORS.length];
  const bubbleBelow = pos ? pos.y < window.innerHeight * 0.5 : true;

  return (
    <div
      ref={wrapRef}
      className={"journey-wrap" + (hopping ? " hopping" : "") + (settled ? " settled" : "")}
      style={pos ? { transform: `translate(${pos.x}px, ${pos.y}px)` } : { opacity: 0 }}
    >
      {bubble ? (
        <div className={"journey-bubble " + (bubbleBelow ? "below" : "above")} key={bubble}><span>{bubble}</span></div>
      ) : null}
      <button
        className={"journey-btn" + (done ? " done" : "")}
        onClick={go}
        aria-label={done ? "Abrir el formulario de registro" : "Ir al siguiente paso de la guía"}
      >
        <span className="journey-ring" aria-hidden="true">
          <svg viewBox="0 0 38 38">
            <circle className="ring-track" cx="19" cy="19" r={R}></circle>
            <circle
              className="ring-fill"
              cx="19" cy="19" r={R}
              strokeDasharray={C}
              strokeDashoffset={C * (1 - pct)}
              style={{ stroke: done ? "#fff" : hopColor }}
            ></circle>
          </svg>
          <span className="journey-core" style={{ color: done ? "#fff" : hopColor }}>{done ? "★" : "★"}</span>
        </span>
        <span className="journey-text">
          <strong>{label}</strong>
          <em>{done ? "¡Guía completa! Abre el registro" : total > 0 ? reached.length + " de " + total + " secciones" : "Tu recorrido"}</em>
        </span>
        <span className="journey-arrow"></span>
      </button>
    </div>
  );
}

Object.assign(window, { JourneyButton });
