"use client";

import { AnimatePresence, motion } from "motion/react";
import {
  createContext,
  useCallback,
  useContext,
  useRef,
  useState,
  type ReactNode,
} from "react";

type Ball = { id: number; startX: number; startY: number; endX: number; endY: number };

type CartFlyContextValue = {
  registerCartIcon: (el: HTMLElement | null) => void;
  fly: (sourceEl: HTMLElement) => void;
  /** Real cart count minus this = what the navbar badge should currently
   * show — held back for as long as a ball is still mid-flight, so the
   * badge only "counts up" once the ball visually lands there. */
  pendingCount: number;
};

const CartFlyContext = createContext<CartFlyContextValue | null>(null);

let ballSeq = 0;

/**
 * Mounted once at the root (app/layout.tsx) so both the cart icon (in
 * Navbar, one branch of the tree) and any add-to-cart button (in page
 * content, a different branch) can share one flight target/queue via
 * context instead of prop-drilling across unrelated component trees.
 */
export function CartFlyProvider({ children }: { children: ReactNode }) {
  const cartIconRef = useRef<HTMLElement | null>(null);
  const [balls, setBalls] = useState<Ball[]>([]);
  const [pendingCount, setPendingCount] = useState(0);

  const registerCartIcon = useCallback((el: HTMLElement | null) => {
    cartIconRef.current = el;
  }, []);

  const fly = useCallback((sourceEl: HTMLElement) => {
    const target = cartIconRef.current;
    if (!target) return;
    const from = sourceEl.getBoundingClientRect();
    const to = target.getBoundingClientRect();
    setBalls((prev) => [
      ...prev,
      {
        id: ++ballSeq,
        startX: from.left + from.width / 2,
        startY: from.top + from.height / 2,
        endX: to.left + to.width / 2,
        endY: to.top + to.height / 2,
      },
    ]);
    setPendingCount((n) => n + 1);
  }, []);

  function handleArrive(id: number) {
    setBalls((prev) => prev.filter((b) => b.id !== id));
    setPendingCount((n) => Math.max(0, n - 1));
  }

  return (
    <CartFlyContext.Provider value={{ registerCartIcon, fly, pendingCount }}>
      {children}
      <AnimatePresence>
        {balls.map((ball) => (
          <motion.div
            key={ball.id}
            initial={{ x: ball.startX, y: ball.startY, opacity: 1, scale: 1.4 }}
            animate={{
              x: ball.endX,
              y: ball.endY,
              scale: 0.6,
              opacity: 0.85,
            }}
            transition={{ duration: 0.85, ease: "easeIn" }}
            onAnimationComplete={() => handleArrive(ball.id)}
            style={{ marginLeft: -12, marginTop: -12 }}
            className="fixed left-0 top-0 z-[100] size-6 rounded-full bg-brand pointer-events-none"
          />
        ))}
      </AnimatePresence>
    </CartFlyContext.Provider>
  );
}

export function useCartFly() {
  const ctx = useContext(CartFlyContext);
  if (!ctx) throw new Error("useCartFly must be used within CartFlyProvider");
  return ctx;
}
