import { useEffect, useRef, useState } from "react";
import { Link } from "react-router-dom";
import {
  Loader2,
  Minus,
  Plus,
  ShoppingBag,
  Trash2,
  X,
} from "lucide-react";
import { useCart } from "@/context/CartContext";
import { formatPrice } from "@/lib/currency";
import { Price } from "@/components/ui/Price";

interface CartDrawerProps {
  open: boolean;
  onClose: () => void;
}

/** Brief busy flag used to show a spinner on a specific cart line while its
 *  quantity is being mutated. Even though the cart store is synchronous, the
 *  UX benefits from a small (sub-300ms) visual confirmation that the action
 *  was registered — this is what users perceive as "loading". */
type BusyLineKey = string;

function lineBusyKey(productId: number, variantLabel: string): BusyLineKey {
  return `${productId}::${variantLabel || ""}`;
}

export default function CartDrawer({ open, onClose }: CartDrawerProps) {
  const { lines, subtotal, itemCount, updateQuantity, removeFromCart } = useCart();
  const [busyLines, setBusyLines] = useState<Set<BusyLineKey>>(new Set());
  // Keys of lines that have appeared since the last render. Used to play the
  // `cart-line-enter` animation exactly once per newly-added cart line.
  const [enteringKeys, setEnteringKeys] = useState<Set<BusyLineKey>>(new Set());
  const seenKeysRef = useRef<Set<BusyLineKey>>(new Set());
  const panelRef = useRef<HTMLElement | null>(null);
  const closeButtonRef = useRef<HTMLButtonElement | null>(null);

  // Detect which lines are brand-new compared to the previous render. We only
  // animate additions — quantity changes and removals are handled separately
  // via the per-line `busy` spinner so we don't re-fire the enter animation on
  // every tick.
  useEffect(() => {
    const currentKeys = new Set(
      lines.map((l) => lineBusyKey(l.product_id, l.variant_label)),
    );
    const newlyAdded: BusyLineKey[] = [];
    currentKeys.forEach((k) => {
      if (!seenKeysRef.current.has(k)) newlyAdded.push(k);
    });
    if (newlyAdded.length > 0) {
      setEnteringKeys((prev) => {
        const next = new Set(prev);
        newlyAdded.forEach((k) => next.add(k));
        return next;
      });
      // Clear the "entering" marker after the animation completes so the class
      // doesn't linger on subsequent re-renders of the same line.
      const t = window.setTimeout(() => {
        setEnteringKeys((prev) => {
          const next = new Set(prev);
          newlyAdded.forEach((k) => next.delete(k));
          return next;
        });
      }, 600);
      // Update the ref so subsequent effect runs don't re-animate the same keys.
      newlyAdded.forEach((k) => seenKeysRef.current.add(k));
      return () => window.clearTimeout(t);
    }
    // Prune keys that no longer exist so a removed-then-re-added line gets
    // animated the next time it appears.
    seenKeysRef.current.forEach((k) => {
      if (!currentKeys.has(k)) seenKeysRef.current.delete(k);
    });
  }, [lines]);

  // --- Body scroll lock while the drawer is open -------------------------
  // We preserve the previous overflow style so we restore the exact original
  // value (which may itself be an inline override set by another component).
  useEffect(() => {
    if (!open) return;
    const { body } = document;
    const previousOverflow = body.style.overflow;
    const previousPaddingRight = body.style.paddingRight;
    // Compensate for the scrollbar to avoid a layout jump on desktop.
    const scrollbarWidth =
      window.innerWidth - document.documentElement.clientWidth;
    body.style.overflow = "hidden";
    if (scrollbarWidth > 0) {
      body.style.paddingRight = `${scrollbarWidth}px`;
    }
    return () => {
      body.style.overflow = previousOverflow;
      body.style.paddingRight = previousPaddingRight;
    };
  }, [open]);

  // --- Close on Escape and focus close button when the drawer opens ------
  useEffect(() => {
    if (!open) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") onClose();
    };
    window.addEventListener("keydown", onKey);
    const t = window.setTimeout(() => closeButtonRef.current?.focus(), 50);
    return () => {
      window.removeEventListener("keydown", onKey);
      window.clearTimeout(t);
    };
  }, [open, onClose]);

  const withBusy = async (key: BusyLineKey, action: () => void) => {
    setBusyLines((prev) => {
      const next = new Set(prev);
      next.add(key);
      return next;
    });
    try {
      action();
    } finally {
      // Short visual delay so the spinner is actually perceptible.
      window.setTimeout(() => {
        setBusyLines((prev) => {
          const next = new Set(prev);
          next.delete(key);
          return next;
        });
      }, 220);
    }
  };

  return (
    <>
      {/* Backdrop */}
      <div
        aria-hidden={!open}
        onClick={onClose}
        className={`fixed inset-0 bg-black/50 backdrop-blur-[2px] z-[60] transition-opacity duration-300 ${
          open ? "opacity-100" : "opacity-0 pointer-events-none"
        }`}
      />
      {/* Panel */}
      <aside
        ref={panelRef}
        className={`fixed top-0 right-0 h-[100dvh] w-[90vw] sm:w-[420px] max-w-[420px] bg-white z-[61] shadow-2xl flex flex-col transition-transform duration-300 ease-out will-change-transform ${
          open ? "translate-x-0" : "translate-x-full"
        }`}
        role="dialog"
        aria-modal="true"
        aria-label="Shopping cart"
        aria-hidden={!open}
      >
        <header className="flex items-center justify-between px-5 py-4 border-b border-slate-200 flex-shrink-0">
          <h2 className="font-bold text-lg text-slate-900 inline-flex items-center gap-2">
            <ShoppingBag className="w-5 h-5 text-[#0b6e3e]" /> Your Cart
            {itemCount > 0 && (
              <span className="ml-1 text-xs font-semibold text-white bg-[#0b6e3e] rounded-full px-2 py-0.5">
                {itemCount}
              </span>
            )}
          </h2>
          <button
            ref={closeButtonRef}
            onClick={onClose}
            className="p-2 rounded-lg hover:bg-slate-100 text-slate-700"
            aria-label="Close cart"
          >
            <X className="w-5 h-5" />
          </button>
        </header>

        {/* Scrollable region. `min-h-0` is critical so this flex child can
            actually shrink and scroll on mobile; otherwise the footer gets
            pushed off-screen on small viewports. `overscroll-contain`
            prevents the mobile rubber-band from scrolling the page behind. */}
        <div className="flex-1 min-h-0 overflow-y-auto overscroll-contain px-5 py-4 space-y-4">
          {lines.length === 0 ? (
            <div className="h-full flex flex-col items-center justify-center text-center text-slate-500 py-16">
              <div className="w-20 h-20 rounded-full bg-slate-100 flex items-center justify-center mb-4">
                <ShoppingBag className="w-10 h-10 text-slate-400" />
              </div>
              <p className="text-lg font-semibold text-slate-800">
                Your cart is empty
              </p>
              <p className="text-sm text-slate-500 mt-1 max-w-[18rem]">
                Browse our shop and add products, hosting plans, or downloads
                to get started.
              </p>
              <Link
                to="/shop"
                onClick={onClose}
                className="mt-5 inline-flex items-center gap-2 px-5 py-2.5 rounded-xl bg-[#0b6e3e] text-white font-semibold hover:bg-[#0a8048] transition-colors"
              >
                Browse shop
              </Link>
            </div>
          ) : (
            lines.map((l) => {
              const key = lineBusyKey(l.product_id, l.variant_label);
              const isBusy = busyLines.has(key);
              const isEntering = enteringKeys.has(key);
              return (
                <div
                  key={key}
                  className={`flex gap-3 border border-slate-200 rounded-xl p-3 bg-white transition-opacity ${
                    isBusy ? "opacity-70" : "opacity-100"
                  } ${isEntering ? "cart-line-enter" : ""}`}
                >
                  <div className="w-20 h-20 rounded-lg bg-slate-50 overflow-hidden flex-shrink-0 relative">
                    {l.image_url ? (
                      <img
                        src={l.image_url}
                        alt={l.name}
                        className="w-full h-full object-cover"
                        loading="lazy"
                      />
                    ) : (
                      <div className="w-full h-full flex items-center justify-center text-slate-300">
                        <ShoppingBag className="w-6 h-6" />
                      </div>
                    )}
                    {isBusy && (
                      <div className="absolute inset-0 flex items-center justify-center bg-white/60">
                        <Loader2 className="w-5 h-5 animate-spin text-[#0b6e3e]" />
                      </div>
                    )}
                  </div>
                  <div className="flex-1 min-w-0">
                    <Link
                      to={`/shop/${l.slug}`}
                      onClick={onClose}
                      className="font-semibold text-sm text-slate-900 hover:text-[#0b6e3e] line-clamp-2"
                    >
                      {l.name}
                    </Link>
                    {l.variant_label && (
                      <div className="text-xs text-slate-500 mt-0.5 truncate">
                        {l.variant_label}
                      </div>
                    )}
                    <div className="text-sm font-bold text-[#0b6e3e] mt-1">
                      <Price amount={l.unit_price} />
                    </div>
                    <div className="flex items-center justify-between mt-2">
                      <div className="inline-flex items-center border border-slate-200 rounded-lg">
                        <button
                          onClick={() =>
                            void withBusy(key, () =>
                              updateQuantity(
                                l.product_id,
                                l.variant_label,
                                l.quantity - 1,
                              ),
                            )
                          }
                          disabled={isBusy || l.quantity <= 1}
                          className="p-1.5 hover:bg-slate-100 disabled:opacity-40"
                          aria-label="Decrease quantity"
                        >
                          <Minus className="w-3.5 h-3.5" />
                        </button>
                        <span className="px-3 text-sm font-semibold min-w-[2rem] text-center">
                          {isBusy ? (
                            <Loader2 className="w-3.5 h-3.5 animate-spin inline" />
                          ) : (
                            l.quantity
                          )}
                        </span>
                        <button
                          onClick={() =>
                            void withBusy(key, () =>
                              updateQuantity(
                                l.product_id,
                                l.variant_label,
                                l.quantity + 1,
                              ),
                            )
                          }
                          disabled={
                            isBusy || (l.stock >= 0 && l.quantity >= l.stock)
                          }
                          className="p-1.5 hover:bg-slate-100 disabled:opacity-40"
                          aria-label="Increase quantity"
                        >
                          <Plus className="w-3.5 h-3.5" />
                        </button>
                      </div>
                      <button
                        onClick={() =>
                          void withBusy(key, () =>
                            removeFromCart(l.product_id, l.variant_label),
                          )
                        }
                        disabled={isBusy}
                        className="text-xs text-rose-600 hover:text-rose-700 inline-flex items-center gap-1 disabled:opacity-50"
                      >
                        <Trash2 className="w-3.5 h-3.5" /> Remove
                      </button>
                    </div>
                  </div>
                </div>
              );
            })
          )}
        </div>

        {lines.length > 0 && (
          <footer className="border-t border-slate-200 px-5 py-4 bg-slate-50 flex-shrink-0 pb-[max(1rem,env(safe-area-inset-bottom))]">
            <div className="flex items-center justify-between mb-3">
              <span className="text-sm text-slate-600">Subtotal</span>
              <span className="text-xl font-extrabold text-slate-900">
                <Price amount={subtotal} />
              </span>
            </div>
            <div className="text-xs text-slate-500 mb-3">
              Shipping and taxes calculated at checkout.
            </div>
            <div className="grid grid-cols-2 gap-3">
              <Link
                to="/shop/cart"
                onClick={onClose}
                className="text-center py-2.5 rounded-xl border border-slate-300 font-semibold text-slate-700 hover:bg-white transition-colors"
              >
                View Cart
              </Link>
              <Link
                to="/shop/checkout"
                onClick={onClose}
                className="text-center py-2.5 rounded-xl bg-[#0b6e3e] text-white font-semibold hover:bg-[#0a8048] transition-colors"
              >
                Checkout
              </Link>
            </div>
          </footer>
        )}
      </aside>
    </>
  );
}