/* ──────────────────────────────────────────────────────────────────────
 * Reliquary Arcanum — Cart + Wishlist
 * ──────────────────────────────────────────────────────────────────────
 *
 * Cart is backed by Shopify's Storefront Cart API. The cart ID is
 * persisted in localStorage so visits resume the same cart. Checkout
 * hands off to Shopify's hosted checkout via cart.checkoutUrl.
 *
 * Wishlist is local-only (an array of product handles in localStorage).
 *
 * Required Storefront API scope (in addition to the read scopes already
 * configured):
 *   ✓ unauthenticated_write_checkouts
 *
 * If SHOPIFY_TOKEN is empty (preview mode), the cart still works as a UI
 * shell — items can be added/removed locally — but the checkout button is
 * disabled and shows a notice. This lets the design preview without a
 * live shop.
 * ──────────────────────────────────────────────────────────────────── */

const RA_CART_KEY     = "ra_cart_id";       // localStorage key for Shopify cart ID
const RA_WISHLIST_KEY = "ra_wishlist";      // localStorage key for wishlist
const RA_CART_EVENT   = "ra:cart-updated";  // window event for cross-mount sync
const RA_WISH_EVENT   = "ra:wishlist-updated";

/* ── Shopify cart GraphQL ─────────────────────────────────────────── */

const CART_FRAGMENT = `
  fragment CartFields on Cart {
    id
    checkoutUrl
    totalQuantity
    cost {
      subtotalAmount { amount currencyCode }
      totalAmount    { amount currencyCode }
    }
    lines(first: 50) {
      edges { node {
        id
        quantity
        merchandise {
          ... on ProductVariant {
            id title availableForSale
            price { amount currencyCode }
            image { url altText }
            product { id handle title }
            selectedOptions { name value }
          }
        }
      } }
    }
  }`;

const M_CART_CREATE = `
  mutation cartCreate($input: CartInput) {
    cartCreate(input: $input) {
      cart { ...CartFields }
      userErrors { field message }
    }
  }
  ${CART_FRAGMENT}`;

const M_CART_LINES_ADD = `
  mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
    cartLinesAdd(cartId: $cartId, lines: $lines) {
      cart { ...CartFields }
      userErrors { field message }
    }
  }
  ${CART_FRAGMENT}`;

const M_CART_LINES_UPDATE = `
  mutation cartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
    cartLinesUpdate(cartId: $cartId, lines: $lines) {
      cart { ...CartFields }
      userErrors { field message }
    }
  }
  ${CART_FRAGMENT}`;

const M_CART_LINES_REMOVE = `
  mutation cartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
    cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
      cart { ...CartFields }
      userErrors { field message }
    }
  }
  ${CART_FRAGMENT}`;

const Q_CART = `
  query getCart($id: ID!) {
    cart(id: $id) { ...CartFields }
  }
  ${CART_FRAGMENT}`;

/* ── Cart shape helpers ───────────────────────────────────────────── */

function normalizeCart(cart) {
  if (!cart) return null;
  return {
    id: cart.id,
    checkoutUrl: cart.checkoutUrl,
    totalQuantity: cart.totalQuantity || 0,
    subtotal: cart.cost?.subtotalAmount
      ? formatPrice(cart.cost.subtotalAmount) : null,
    total:    cart.cost?.totalAmount
      ? formatPrice(cart.cost.totalAmount) : null,
    currencyCode: cart.cost?.totalAmount?.currencyCode || "USD",
    lines: (cart.lines?.edges || []).map(e => {
      const v = e.node.merchandise || {};
      return {
        lineId: e.node.id,
        quantity: e.node.quantity,
        variantId: v.id,
        variantTitle: v.title,
        available: v.availableForSale,
        price: v.price ? formatPrice(v.price) : null,
        image: v.image?.url || null,
        imageAlt: v.image?.altText || v.product?.title || "",
        productHandle: v.product?.handle,
        productTitle:  v.product?.title || v.title,
        options: v.selectedOptions || [],
      };
    }),
  };
}

/* ── Local-only "preview cart" used when Shopify isn't configured ── */

const PREVIEW_CART_KEY = "ra_preview_cart";

function loadPreviewCart() {
  try {
    const raw = localStorage.getItem(PREVIEW_CART_KEY);
    if (!raw) return { id: "preview", checkoutUrl: null, totalQuantity: 0, lines: [] };
    const parsed = JSON.parse(raw);
    parsed.totalQuantity = parsed.lines.reduce((n, l) => n + l.quantity, 0);
    return parsed;
  } catch {
    return { id: "preview", checkoutUrl: null, totalQuantity: 0, lines: [] };
  }
}

function savePreviewCart(cart) {
  try { localStorage.setItem(PREVIEW_CART_KEY, JSON.stringify(cart)); } catch {}
}

function previewAddLine(cart, line) {
  const existing = cart.lines.find(l => l.variantId === line.variantId);
  if (existing) existing.quantity += line.quantity;
  else cart.lines.push({ ...line, lineId: `preview-${Date.now()}-${Math.random()}` });
  cart.totalQuantity = cart.lines.reduce((n, l) => n + l.quantity, 0);
  savePreviewCart(cart);
  return cart;
}

function previewUpdateLine(cart, lineId, quantity) {
  const line = cart.lines.find(l => l.lineId === lineId);
  if (line) {
    if (quantity <= 0) cart.lines = cart.lines.filter(l => l.lineId !== lineId);
    else line.quantity = quantity;
  }
  cart.totalQuantity = cart.lines.reduce((n, l) => n + l.quantity, 0);
  savePreviewCart(cart);
  return cart;
}

function previewRemoveLine(cart, lineId) {
  cart.lines = cart.lines.filter(l => l.lineId !== lineId);
  cart.totalQuantity = cart.lines.reduce((n, l) => n + l.quantity, 0);
  savePreviewCart(cart);
  return cart;
}

/* ── Public Shopify cart API ──────────────────────────────────────── */

async function shopifyCartCreate(lines = []) {
  const data = await shopifyQuery(M_CART_CREATE, {
    input: lines.length ? { lines } : {},
  });
  const r = data.cartCreate;
  if (r.userErrors?.length) throw new Error(r.userErrors[0].message);
  return r.cart;
}

async function shopifyCartGet(cartId) {
  const data = await shopifyQuery(Q_CART, { id: cartId });
  return data.cart; // null if cart no longer exists (e.g. completed)
}

async function shopifyCartLinesAdd(cartId, lines) {
  const data = await shopifyQuery(M_CART_LINES_ADD, { cartId, lines });
  const r = data.cartLinesAdd;
  if (r.userErrors?.length) throw new Error(r.userErrors[0].message);
  return r.cart;
}

async function shopifyCartLinesUpdate(cartId, lines) {
  const data = await shopifyQuery(M_CART_LINES_UPDATE, { cartId, lines });
  const r = data.cartLinesUpdate;
  if (r.userErrors?.length) throw new Error(r.userErrors[0].message);
  return r.cart;
}

async function shopifyCartLinesRemove(cartId, lineIds) {
  const data = await shopifyQuery(M_CART_LINES_REMOVE, { cartId, lineIds });
  const r = data.cartLinesRemove;
  if (r.userErrors?.length) throw new Error(r.userErrors[0].message);
  return r.cart;
}

/* ── React hook: cart state ───────────────────────────────────────── */

function useCart() {
  const [cart, setCart] = React.useState(null);
  const [status, setStatus] = React.useState(SHOPIFY_CONFIGURED ? "loading" : "preview");
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);

  /* Initial load (and re-load when another mount on the page triggers an update) */
  const reload = React.useCallback(async () => {
    if (!SHOPIFY_CONFIGURED) {
      setCart(loadPreviewCart());
      setStatus("preview");
      return;
    }
    const id = localStorage.getItem(RA_CART_KEY);
    if (!id) { setCart(null); setStatus("ready"); return; }
    try {
      const c = await shopifyCartGet(id);
      if (!c) {
        // Cart expired or was completed; clear and start fresh on next add
        localStorage.removeItem(RA_CART_KEY);
        setCart(null);
      } else {
        setCart(normalizeCart(c));
      }
      setStatus("ready");
    } catch (e) {
      setError(e.message);
      setStatus("ready");
    }
  }, []);

  React.useEffect(() => {
    reload();
    const onUpdate = () => reload();
    window.addEventListener(RA_CART_EVENT, onUpdate);
    return () => window.removeEventListener(RA_CART_EVENT, onUpdate);
  }, [reload]);

  const broadcast = () => window.dispatchEvent(new Event(RA_CART_EVENT));

  /* Add a line. `merchandiseId` is a Shopify variant gid. In preview mode
     we accept a `previewLine` with display fields baked in. */
  const addLine = React.useCallback(async ({ merchandiseId, quantity = 1, previewLine = null }) => {
    setBusy(true); setError(null);
    try {
      if (!SHOPIFY_CONFIGURED) {
        if (!previewLine) throw new Error("Preview mode requires previewLine data");
        const c = previewAddLine(loadPreviewCart(), { ...previewLine, quantity });
        setCart(c); broadcast(); return c;
      }
      const lines = [{ merchandiseId, quantity }];
      let cartId = localStorage.getItem(RA_CART_KEY);
      let raw;
      if (!cartId) {
        raw = await shopifyCartCreate(lines);
        localStorage.setItem(RA_CART_KEY, raw.id);
      } else {
        raw = await shopifyCartLinesAdd(cartId, lines);
      }
      const norm = normalizeCart(raw);
      setCart(norm); broadcast(); return norm;
    } catch (e) {
      setError(e.message);
      throw e;
    } finally {
      setBusy(false);
    }
  }, []);

  const updateLine = React.useCallback(async (lineId, quantity) => {
    setBusy(true); setError(null);
    try {
      if (!SHOPIFY_CONFIGURED) {
        const c = previewUpdateLine(loadPreviewCart(), lineId, quantity);
        setCart(c); broadcast(); return c;
      }
      const cartId = localStorage.getItem(RA_CART_KEY);
      if (!cartId) return null;
      const raw = quantity <= 0
        ? await shopifyCartLinesRemove(cartId, [lineId])
        : await shopifyCartLinesUpdate(cartId, [{ id: lineId, quantity }]);
      const norm = normalizeCart(raw);
      setCart(norm); broadcast(); return norm;
    } catch (e) {
      setError(e.message);
      throw e;
    } finally {
      setBusy(false);
    }
  }, []);

  const removeLine = React.useCallback(async (lineId) => {
    setBusy(true); setError(null);
    try {
      if (!SHOPIFY_CONFIGURED) {
        const c = previewRemoveLine(loadPreviewCart(), lineId);
        setCart(c); broadcast(); return c;
      }
      const cartId = localStorage.getItem(RA_CART_KEY);
      if (!cartId) return null;
      const raw = await shopifyCartLinesRemove(cartId, [lineId]);
      const norm = normalizeCart(raw);
      setCart(norm); broadcast(); return norm;
    } catch (e) {
      setError(e.message);
      throw e;
    } finally {
      setBusy(false);
    }
  }, []);

  return { cart, status, busy, error, addLine, updateLine, removeLine, reload };
}

/* ── Wishlist (local only) ─────────────────────────────────────────── */

function loadWishlist() {
  try {
    const raw = localStorage.getItem(RA_WISHLIST_KEY);
    return raw ? JSON.parse(raw) : [];
  } catch { return []; }
}

function saveWishlist(arr) {
  try { localStorage.setItem(RA_WISHLIST_KEY, JSON.stringify(arr)); } catch {}
  window.dispatchEvent(new Event(RA_WISH_EVENT));
}

function useWishlist() {
  const [items, setItems] = React.useState(() => loadWishlist());
  React.useEffect(() => {
    const onUpdate = () => setItems(loadWishlist());
    window.addEventListener(RA_WISH_EVENT, onUpdate);
    return () => window.removeEventListener(RA_WISH_EVENT, onUpdate);
  }, []);
  const has = React.useCallback((handle) => items.includes(handle), [items]);
  const toggle = React.useCallback((handle) => {
    if (!handle) return;
    const next = items.includes(handle)
      ? items.filter(h => h !== handle)
      : [...items, handle];
    saveWishlist(next);
    setItems(next);
  }, [items]);
  return { items, count: items.length, has, toggle };
}

/* ── Cart drawer component ────────────────────────────────────────── */

function CartDrawer({ open, onClose }) {
  const { cart, busy, error, updateLine, removeLine } = useCart();
  const lines = cart?.lines || [];
  const totalQty = cart?.totalQuantity || 0;
  const isPreview = !SHOPIFY_CONFIGURED;

  // Lock body scroll while drawer is open
  React.useEffect(() => {
    if (open) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      return () => { document.body.style.overflow = prev; };
    }
  }, [open]);

  // Close on Escape
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);

  const checkout = () => {
    if (isPreview || !cart?.checkoutUrl) return;
    window.location.href = cart.checkoutUrl;
  };

  return (
    <>
      <div className={`ra-cart-overlay ${open ? "open" : ""}`} onClick={onClose} aria-hidden={!open}/>
      <aside className={`ra-cart-drawer ${open ? "open" : ""}`} role="dialog" aria-label="Cart">
        <header className="ra-cart-head">
          <span className="ra-cart-eyebrow">Your Reliquary</span>
          <span className="ra-cart-count">{totalQty} {totalQty === 1 ? "piece" : "pieces"}</span>
          <button className="ra-cart-close" onClick={onClose} aria-label="Close cart">&times;</button>
        </header>

        {isPreview && (
          <div className="ra-cart-notice">
            Preview mode — items are saved locally for design review only. Connect Shopify to enable real checkout.
          </div>
        )}
        {error && <div className="ra-cart-notice error">Cart error: {error}</div>}

        <div className="ra-cart-body">
          {lines.length === 0 ? (
            <div className="ra-cart-empty">
              <p className="ra-cart-empty-title">Your reliquary is empty.</p>
              <p className="ra-cart-empty-sub">"Every piece begins with a moment of recognition."</p>
            </div>
          ) : lines.map(line => (
            <div className="ra-cart-line" key={line.lineId}>
              {line.image && <img src={line.image} alt={line.imageAlt} className="ra-cart-line-img"/>}
              <div className="ra-cart-line-info">
                <a className="ra-cart-line-name"
                   href={line.productHandle ? `${RA_LINKS.product}?handle=${encodeURIComponent(line.productHandle)}` : "#"}>
                  {line.productTitle}
                </a>
                {line.variantTitle && line.variantTitle !== "Default Title" && (
                  <div className="ra-cart-line-variant">{line.variantTitle}</div>
                )}
                <div className="ra-cart-line-price">{line.price}</div>
                <div className="ra-cart-line-actions">
                  <div className="ra-cart-qty">
                    <button onClick={() => updateLine(line.lineId, line.quantity - 1)} disabled={busy} aria-label="Decrease quantity">−</button>
                    <span>{line.quantity}</span>
                    <button onClick={() => updateLine(line.lineId, line.quantity + 1)} disabled={busy} aria-label="Increase quantity">+</button>
                  </div>
                  <button className="ra-cart-remove" onClick={() => removeLine(line.lineId)} disabled={busy}>Remove</button>
                </div>
              </div>
            </div>
          ))}
        </div>

        {lines.length > 0 && (
          <footer className="ra-cart-foot">
            {cart?.subtotal && (
              <div className="ra-cart-subtotal">
                <span className="ra-cart-subtotal-label">Subtotal</span>
                <span className="ra-cart-subtotal-val">{cart.subtotal}</span>
              </div>
            )}
            <p className="ra-cart-meta">Shipping & taxes calculated at checkout · Free shipping over $250</p>
            <button className="btn btn-solid ra-cart-checkout"
                    onClick={checkout}
                    disabled={busy || isPreview || !cart?.checkoutUrl}>
              {isPreview ? "Checkout disabled in preview" : busy ? "Working…" : "Proceed to Checkout"}
            </button>
          </footer>
        )}
      </aside>
    </>
  );
}

/* ── "Add to cart" toast (bottom-right) ───────────────────────────── */

function CartToast({ visible, onOpen, onDismiss, title }) {
  React.useEffect(() => {
    if (!visible) return;
    const t = setTimeout(onDismiss, 4500);
    return () => clearTimeout(t);
  }, [visible, onDismiss]);
  if (!visible) return null;
  return (
    <div className="ra-cart-toast" role="status" aria-live="polite">
      <div className="ra-cart-toast-text">
        <div className="ra-cart-toast-eyebrow">Added to your reliquary</div>
        <div className="ra-cart-toast-title">{title}</div>
      </div>
      <button className="ra-cart-toast-cta" onClick={onOpen}>View cart</button>
    </div>
  );
}

/* ── Top-level provider that owns drawer + toast ───────────────────── */
/*
 * Pages use <RA_CartHost/> as a sibling somewhere in their tree, then read
 * `window.__raCart` for { open, close, addLine, ... } from anywhere.
 *
 * This single-host pattern avoids prop drilling between RA_Nav and the
 * product page's CTA button.
 */
function RA_CartHost() {
  const [open, setOpen] = React.useState(false);
  const [toast, setToast] = React.useState(null);
  const cart = useCart();

  const api = React.useMemo(() => ({
    open:    () => setOpen(true),
    close:   () => setOpen(false),
    addLine: async ({ merchandiseId, quantity = 1, previewLine = null, productTitle = "Item" }) => {
      const result = await cart.addLine({ merchandiseId, quantity, previewLine });
      setToast({ title: productTitle });
      return result;
    },
  }), [cart]);

  React.useEffect(() => {
    window.__raCart = api;
    return () => { if (window.__raCart === api) delete window.__raCart; };
  }, [api]);

  return (
    <>
      <CartDrawer open={open} onClose={() => setOpen(false)}/>
      <CartToast visible={!!toast}
                 title={toast?.title}
                 onOpen={() => { setToast(null); setOpen(true); }}
                 onDismiss={() => setToast(null)}/>
    </>
  );
}

/* ── Tiny helpers used by the nav and product pages ────────────────── */

function useCartCount() {
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    const refresh = () => {
      if (!SHOPIFY_CONFIGURED) {
        setN(loadPreviewCart().totalQuantity);
        return;
      }
      const id = localStorage.getItem(RA_CART_KEY);
      if (!id) { setN(0); return; }
      shopifyCartGet(id).then(c => setN(c?.totalQuantity || 0)).catch(() => {});
    };
    refresh();
    window.addEventListener(RA_CART_EVENT, refresh);
    return () => window.removeEventListener(RA_CART_EVENT, refresh);
  }, []);
  return n;
}

function openCart() { window.__raCart?.open(); }

Object.assign(window, {
  // public API
  useCart, useWishlist, useCartCount, openCart,
  CartDrawer, CartToast, RA_CartHost,
  // internals (exposed for debugging)
  RA_CART_KEY, RA_WISHLIST_KEY, RA_CART_EVENT, RA_WISH_EVENT,
  loadPreviewCart, loadWishlist,
});
