// FireTail portfolio — shared-element social dock.
// ONE element with three scroll-driven homes:
//   float  → collapsed bubble bottom-right; fold-out on hover (desktop) / tap (mobile)
//   card   → travels into #ft-anchor-card slot, auto-unfolded, icons only
//   footer → travels into #ft-anchor-footer slot, auto-unfolded WITH labels
// Mode is computed each frame from anchor rects; the dock's RIGHT edge is pinned
// to the target right edge so fold-out width changes never shift it.

function FlameGlyph() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" style={{ display: "block" }}>
      <path d="M13 2c-.6 4.2 3.2 5.6 3.2 9.8 0 3.3-1.9 6.2-4.2 6.2-2.4 0-4.4-2.3-4.4-5.4 0-2.4 1.6-3.1 2.3-5.2.5 2.1 2.1 1.9 2.1-1 0-2.3-.6-3.4-1-4.4C12 3.6 12.6 2.8 13 2Z" />
      <path d="M12 12.5c-.3 1.8 1.4 2 1.4 3.8 0 1.3-.8 2.4-1.7 2.4-1 0-1.8-1-1.8-2.2 0-1 .7-1.3 1-2.2.2.9.9.8.9-.5 0-.6-.2-.9-.2-1.3.2.1.3.1.4.2Z" fill="var(--spark-400)" opacity="0.9" />
    </svg>
  );
}

function BottomDock() {
  const dockRef = React.useRef(null);
  const stateRef = React.useRef({ hovered: false, tapped: false, prevMode: null, travel: 0, x: null, y: null });

  React.useEffect(() => {
    const dock = dockRef.current;
    const scroller = document.querySelector("#ft-scroll");
    if (!dock) return;
    const st = stateRef.current;
    const isTouch = window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
    const reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const items = Array.from(dock.querySelectorAll(".ft-sdock-item"));
    if (reduced) {
      // CSS max-width/opacity transitions don't progress under reduced-motion —
      // disable them so the inline open/label state below applies instantly.
      items.forEach((it) => {
        it.style.transition = "none";
        const lbl = it.querySelector(".ft-sdock-label");
        if (lbl) lbl.style.transition = "none";
      });
    }

    const margin = () => Math.max(14, Math.min(26, window.innerWidth * 0.024));

    // ── card expand / dock sequencing ──
    let cardExpanded = false;
    let cardExpandedAt = 0;
    let cardShrinkAt = 0;
    const EXPAND_MS = 400;
    const SHRINK_DELAY = 300;

    let raf = 0;
    const frame = () => {
      const vw = window.innerWidth, vh = window.innerHeight;
      const now = performance.now();
      const cardA = document.querySelector("#ft-anchor-card");
      const footA = document.querySelector("#ft-anchor-footer");

      const dockBot = vh - 56;
      const HYSTERESIS = 50;
      const enterTop = vh * 0.75;
      const exitTop  = enterTop - HYSTERESIS;

      // ── card zone check with hysteresis ──
      let cardInZone = false;
      if (cardA) {
        const r = cardA.getBoundingClientRect();
        if (!cardExpanded) {
          cardInZone = r.top >= enterTop && r.top <= dockBot;
        } else {
          cardInZone = r.top >= exitTop && r.top <= dockBot;
        }
      }

      // ── card expand / collapse (card's own behavior) ──
      if (cardA) {
        if (cardInZone && !cardExpanded) {
          cardA.style.height = "42px";
          cardA.style.marginTop = "18px";
          cardExpanded = true;
          cardExpandedAt = now;
          cardShrinkAt = 0;
        }
        if (cardInZone) cardShrinkAt = 0;
        if (!cardInZone && cardExpanded) {
          if (!cardShrinkAt) cardShrinkAt = now;
          if (now - cardShrinkAt > SHRINK_DELAY) {
            cardA.style.height = "0px";
            cardA.style.marginTop = "0px";
            cardExpanded = false;
            cardShrinkAt = 0;
          }
        }
      }

      // ── decide mode ──
      let mode = "float";
      if (cardExpanded && cardInZone && now - cardExpandedAt > EXPAND_MS) {
        mode = "card";
      }
      if (footA) {
        const r = footA.getBoundingClientRect();
        if (r.top >= enterTop && r.top <= dockBot) mode = "footer";
      }

      const interaction = st.hovered || st.tapped;
      const isOpen = mode !== "float" || interaction;
      const isLabels = mode === "footer" && vw >= 768;

      dock.classList.toggle("is-open", isOpen);
      dock.classList.toggle("is-labels", isLabels);
      dock.classList.toggle("is-docked", mode !== "float");

      // Drive open/label state via inline styles (authoritative) so it works even
      // when the CSS transition can't run (reduced-motion). The CSS transition,
      // when allowed, simply smooths these inline changes.
      items.forEach((it) => {
        it.style.maxWidth = isOpen ? "260px" : "0px";
        it.style.opacity = isOpen ? "1" : "0";
        it.style.marginLeft = isOpen ? "8px" : "0px";
        it.style.padding = isOpen ? "0 11px" : "0px";
        it.style.borderColor = isOpen ? "var(--border-strong)" : "transparent";
        const lbl = it.querySelector(".ft-sdock-label");
        if (lbl) {
          lbl.style.maxWidth = isLabels ? "150px" : "0px";
          lbl.style.opacity = isLabels ? "1" : "0";
          lbl.style.marginLeft = isLabels ? "9px" : "0px";
        }
      });

      // ── compute target: pin RIGHT edge to target right edge ──
      const rect = dock.getBoundingClientRect();
      let rightX, topY;
      if (mode === "card" && cardA) {
        const r = cardA.getBoundingClientRect();
        rightX = r.right; topY = r.top + (r.height - rect.height) / 2;
      } else if (mode === "footer" && footA) {
        const r = footA.getBoundingClientRect();
        rightX = r.right; topY = r.top + (r.height - rect.height) / 2;
      } else {
        const m = margin();
        rightX = vw - m; topY = vh - m - rect.height;
      }
      const tx = rightX - rect.width, ty = topY;

      // ── mode change kicks off a brief JS-eased "travel"; otherwise track instantly ──
      let k = 1;
      if (mode !== st.prevMode) { st.travel = 30; st.prevMode = mode; }
      if (st.travel > 0) { k = 0.16; st.travel -= 1; }

      if (st.x == null) { st.x = tx; st.y = ty; }   // first frame: snap
      st.x += (tx - st.x) * k;
      st.y += (ty - st.y) * k;

      dock.style.left = st.x + "px";
      dock.style.top = st.y + "px";
      if (dock.style.opacity !== "1") dock.style.opacity = "1";

      raf = requestAnimationFrame(frame);
    };
    raf = requestAnimationFrame(frame);

    // hover (desktop) opens float bubble
    const onEnter = () => { st.hovered = true; };
    const onLeave = () => { st.hovered = false; };
    if (!isTouch) {
      dock.addEventListener("mouseenter", onEnter);
      dock.addEventListener("mouseleave", onLeave);
    }
    // outside tap closes (mobile)
    const onDocClick = (e) => { if (!dock.contains(e.target)) st.tapped = false; };
    document.addEventListener("click", onDocClick);

    return () => {
      cancelAnimationFrame(raf);
      dock.removeEventListener("mouseenter", onEnter);
      dock.removeEventListener("mouseleave", onLeave);
      document.removeEventListener("click", onDocClick);
    };
  }, []);

  const onBubble = (e) => {
    const dock = dockRef.current;
    const docked = dock && dock.classList.contains("is-docked");
    const isTouch = window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
    // Mobile float: tap toggles the fold-out so icons are reachable.
    if (!docked && isTouch) {
      e.preventDefault(); e.stopPropagation();
      stateRef.current.tapped = !stateRef.current.tapped;
      return;
    }
    // Otherwise the bubble is the back-to-top button.
    e.preventDefault();
    const scroller = document.querySelector("#ft-scroll");
    const reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (scroller) scroller.scrollTo({ top: 0, behavior: reduced ? "auto" : "smooth" });
  };

  return (
    <div className="ft-sdock" ref={dockRef} aria-label="Social links" style={{ opacity: 0 }}>
      <div className="ft-sdock-items">
        {SOCIALS.map((s) => (
          <a key={s.key} className="ft-sdock-item" href={s.href}
            target={s.mail ? undefined : "_blank"} rel="noreferrer" title={s.label} aria-label={s.label}>
            <span className="ft-sdock-ic"><SocialIcon s={s} size={18} color="currentColor" /></span>
            <span className="ft-sdock-label">{s.label}</span>
          </a>
        ))}
      </div>
      <button className="ft-sdock-bubble" type="button" onClick={onBubble} aria-label="Back to top" title="Back to top">
        <FlameGlyph />
      </button>
    </div>
  );
}

window.BottomDock = BottomDock;
