/* ──────────────────────────────────────────────────────────────────────
 * Reliquary Arcanum — Shopify Storefront API client
 * ──────────────────────────────────────────────────────────────────────
 *
 * SETUP (one-time, ~3 minutes):
 *
 *   1. Shopify Admin → Apps and sales channels → "Develop apps"
 *      (you may need to enable custom app development first).
 *   2. Click "Create an app". Name it "Reliquary Storefront".
 *   3. Configuration → Storefront API → "Configure".
 *      Enable these scopes:
 *        ✓ unauthenticated_read_product_listings
 *        ✓ unauthenticated_read_product_inventory
 *        ✓ unauthenticated_read_product_tags
 *        ✓ unauthenticated_read_collection_listings
 *      Save.
 *   4. API credentials → "Install app" → confirm.
 *   5. Copy the "Storefront API access token" (starts with shpat_ or a hex string).
 *   6. Paste your shop domain and token below. That's it.
 *
 * The Storefront API is PUBLIC — this token is safe in client-side code.
 * It only allows reading published products, no admin access.
 *
 * If SHOPIFY_TOKEN is empty, every page falls back to placeholder data
 * so you can preview the design before connecting.
 * ──────────────────────────────────────────────────────────────────── */

const SHOPIFY_DOMAIN = "reliquary-arcanum.myshopify.com"; // change if your .myshopify.com domain differs
const SHOPIFY_TOKEN  = "";                                // ← paste Storefront API access token here
const SHOPIFY_API    = "2024-10";

const SHOPIFY_CONFIGURED = SHOPIFY_TOKEN.length > 0;

async function shopifyQuery(query, variables = {}) {
  if (!SHOPIFY_CONFIGURED) throw new Error("Shopify not configured");
  const res = await fetch(`https://${SHOPIFY_DOMAIN}/api/${SHOPIFY_API}/graphql.json`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Storefront-Access-Token": SHOPIFY_TOKEN,
      "Accept": "application/json",
    },
    body: JSON.stringify({ query, variables }),
  });
  if (!res.ok) throw new Error(`Shopify HTTP ${res.status}`);
  const j = await res.json();
  if (j.errors) throw new Error(j.errors[0]?.message || "Shopify GraphQL error");
  return j.data;
}

const Q_COLLECTION = `
  query getCollection($handle: String!, $first: Int!, $filters: [ProductFilter!]) {
    collection(handle: $handle) {
      title
      description
      products(first: $first, filters: $filters) {
        edges { node {
          id handle title productType tags availableForSale
          priceRange { minVariantPrice { amount currencyCode } }
          featuredImage { url altText }
          images(first: 2) { edges { node { url altText } } }
        } }
      }
    }
  }`;

const Q_PRODUCT_TYPES = `
  query getCollectionTypes($handle: String!) {
    collection(handle: $handle) {
      products(first: 250) { edges { node { productType } } }
    }
  }`;

const Q_PRODUCT = `
  query getProduct($handle: String!) {
    product(handle: $handle) {
      id handle title descriptionHtml productType tags availableForSale totalInventory
      priceRange { minVariantPrice { amount currencyCode } }
      images(first: 12) { edges { node { url altText } } }
      options { name values }
      variants(first: 50) {
        edges { node {
          id title availableForSale quantityAvailable
          price { amount currencyCode }
          selectedOptions { name value }
        } }
      }
    }
  }`;

const Q_PRODUCTS_BY_TAG = `
  query getProductsByTag($query: String!, $first: Int!) {
    products(first: $first, query: $query) {
      edges { node {
        id handle title productType tags availableForSale
        priceRange { minVariantPrice { amount currencyCode } }
        featuredImage { url altText }
      } }
    }
  }`;

/* ── Public helpers ───────────────────────────────────────────────── */

async function fetchCollection(handle, { type = null, first = 50 } = {}) {
  const filters = type ? [{ productType: type }] : null;
  const data = await shopifyQuery(Q_COLLECTION, { handle, first, filters });
  if (!data?.collection) return null;
  return {
    title: data.collection.title,
    description: data.collection.description,
    products: data.collection.products.edges.map(e => normalizeProduct(e.node)),
  };
}

async function fetchCollectionTypes(handle) {
  const data = await shopifyQuery(Q_PRODUCT_TYPES, { handle });
  if (!data?.collection) return [];
  const set = new Set();
  data.collection.products.edges.forEach(e => {
    const t = (e.node.productType || "").trim();
    if (t) set.add(t);
  });
  return [...set].sort();
}

async function fetchProduct(handle) {
  const data = await shopifyQuery(Q_PRODUCT, { handle });
  if (!data?.product) return null;
  const p = data.product;
  return {
    id: p.id, handle: p.handle, title: p.title,
    descriptionHtml: p.descriptionHtml, productType: p.productType,
    tags: p.tags || [],
    available: p.availableForSale,
    totalInventory: p.totalInventory,
    price: formatPrice(p.priceRange.minVariantPrice),
    priceRaw: p.priceRange.minVariantPrice,
    images: p.images.edges.map(e => ({ url: e.node.url, alt: e.node.altText || p.title })),
    options: p.options || [],
    variants: p.variants.edges.map(e => ({
      id: e.node.id,
      title: e.node.title,
      available: e.node.availableForSale,
      quantity: e.node.quantityAvailable,
      price: formatPrice(e.node.price),
      selectedOptions: e.node.selectedOptions,
    })),
  };
}

async function fetchProductsByTag(tag, { first = 24 } = {}) {
  const q = `tag:${JSON.stringify(tag)}`;
  const data = await shopifyQuery(Q_PRODUCTS_BY_TAG, { query: q, first });
  return data.products.edges.map(e => normalizeProduct(e.node));
}

function normalizeProduct(n) {
  const tags = n.tags || [];
  const isOOAK = tags.some(t => /one[\s-]?of[\s-]?a[\s-]?kind|ooak|1\s*of\s*1/i.test(t));
  const isMTO  = tags.some(t => /made[\s-]?to[\s-]?order|mto|commission/i.test(t));
  return {
    id: n.id, handle: n.handle, name: n.title,
    type: n.productType || "",
    tags,
    available: n.availableForSale,
    price: formatPrice(n.priceRange.minVariantPrice),
    image: n.featuredImage?.url || n.images?.edges?.[0]?.node?.url || RA_PRODUCT_IMG,
    imageAlt: n.featuredImage?.altText || n.title,
    badge: isOOAK ? "1 of 1" : isMTO ? "MTO" : null,
    tagLabel: isOOAK ? "One of a Kind" : isMTO ? "Made to Order" : (n.productType || "Handcrafted"),
  };
}

function formatPrice({ amount, currencyCode }) {
  const n = parseFloat(amount);
  const sym = currencyCode === "USD" ? "$" : (currencyCode + " ");
  return `${sym}${n % 1 === 0 ? n.toFixed(0) : n.toFixed(2)}`;
}

function getURLParam(name) {
  return new URLSearchParams(window.location.search).get(name);
}

/* React hook: load collection w/ optional type filter, fall back to placeholder */
function useCollection(handle, { type = null, fallback = [] } = {}) {
  const [state, setState] = React.useState({ status: SHOPIFY_CONFIGURED ? "loading" : "fallback", products: fallback, types: [], error: null, title: null });
  React.useEffect(() => {
    if (!SHOPIFY_CONFIGURED) return;
    let cancelled = false;
    (async () => {
      try {
        const [coll, types] = await Promise.all([
          fetchCollection(handle, { type }),
          fetchCollectionTypes(handle).catch(() => []),
        ]);
        if (cancelled) return;
        if (!coll) {
          setState({ status: "fallback", products: fallback, types: [], error: "Collection not found", title: null });
        } else {
          setState({ status: "ready", products: coll.products, types, error: null, title: coll.title });
        }
      } catch (e) {
        if (cancelled) return;
        setState({ status: "fallback", products: fallback, types: [], error: e.message, title: null });
      }
    })();
    return () => { cancelled = true; };
  }, [handle, type]);
  return state;
}

/* React hook: load single product by ?handle= */
function useProduct({ fallback = null } = {}) {
  const handle = getURLParam("handle");
  const [state, setState] = React.useState({
    status: SHOPIFY_CONFIGURED && handle ? "loading" : "fallback",
    product: fallback, error: null,
  });
  React.useEffect(() => {
    if (!SHOPIFY_CONFIGURED || !handle) return;
    let cancelled = false;
    (async () => {
      try {
        const p = await fetchProduct(handle);
        if (cancelled) return;
        if (!p) setState({ status: "fallback", product: fallback, error: "Not found" });
        else    setState({ status: "ready", product: p, error: null });
      } catch (e) {
        if (cancelled) return;
        setState({ status: "fallback", product: fallback, error: e.message });
      }
    })();
    return () => { cancelled = true; };
  }, [handle]);
  return { ...state, handle };
}

/* Small UI banner shown when running on placeholder data */
function ShopifyStatusBanner({ state, hint }) {
  if (state?.status === "ready") return null;
  const msg = !SHOPIFY_CONFIGURED
    ? "Preview mode — placeholder data. Add your Storefront API token in ra-shopify.jsx to load real products."
    : state?.status === "loading"
      ? "Loading from Shopify…"
      : `Shopify fallback active${state?.error ? ` — ${state.error}` : ""}. Showing placeholder data.${hint ? " " + hint : ""}`;
  const tone = state?.status === "loading" ? "var(--muted)" : "var(--gold)";
  return (
    <div style={{
      padding:"10px 52px", borderBottom:"1px solid var(--rule)",
      fontFamily:"var(--sans)", fontSize:10, letterSpacing:"0.22em",
      textTransform:"uppercase", color: tone, background:"rgba(192,158,80,0.04)",
      textAlign:"center"
    }}>{msg}</div>
  );
}

Object.assign(window, {
  SHOPIFY_DOMAIN, SHOPIFY_TOKEN, SHOPIFY_CONFIGURED,
  fetchCollection, fetchCollectionTypes, fetchProduct, fetchProductsByTag,
  useCollection, useProduct, getURLParam, formatPrice,
  ShopifyStatusBanner,
});
