/* global React, ReactDOM */
// ============================================================
// Disco Gringo · WAVE AIR — shared primitives, data, hooks.
// Everything here is published to window.DGShop for the other
// babel modules (each script gets its own scope).
// ============================================================
const { useState, useEffect, useRef, useContext, createContext, useCallback } = React;

// ---------- Lucide icon ----------
function Icon({ name, size = 22, strokeWidth = 2.25, color = "currentColor", style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current || !window.lucide) return;
    ref.current.innerHTML = `<i data-lucide="${name}"></i>`;
    try {
      window.lucide.createIcons({ attrs: { "stroke-width": strokeWidth }, nameAttr: "data-lucide", root: ref.current });
    } catch (e) {
      window.lucide.createIcons();
    }
  });
  return <span ref={ref} className="dg-ic" style={{ fontSize: size, color, display: "inline-flex", ...style }} />;
}

// ---------- Product ----------
const PRODUCT = {
  name: "WAVE AIR",
  sub: "The Drop Tee",
  price: 38,
  compareAt: 48,
  blurb:
    "Heavyweight 240gsm tee with the whole jungle disco printed across the front — the WAVE AIR jet, parachuting vinyl, and the crowd losing it under the palms. A one-and-only drop.",
  art: "assets/wave-air-tee-web.png",
  colors: [
    { key: "white", name: "Tee White", bg: "var(--paper)", ring: "var(--ink-900)" },
    { key: "pink", name: "Bubblegum", bg: "var(--pink-300)", ring: "var(--pink-300)" },
    { key: "teal", name: "Jade Teal", bg: "var(--teal-400)", ring: "var(--teal-400)" },
    { key: "ink", name: "Ink Black", bg: "var(--ink-900)", ring: "var(--ink-900)" },
  ],
  sizes: [
    { k: "XS", on: true }, { k: "S", on: true }, { k: "M", on: true },
    { k: "L", on: true }, { k: "XL", on: true }, { k: "2XL", on: false },
  ],
  details: [
    ["Fabric", "100% ringspun cotton, 240gsm heavyweight"],
    ["Print", "Full-front DTG, pink + jade + ink on garment"],
    ["Fit", "Boxy unisex — size down for fitted"],
    ["Drop", "Limited run · numbered · ships from Palmas"],
  ],
};
const money = (n) => "$" + Number(n).toFixed(n % 1 === 0 ? 0 : 2);

// ---------- Shop context (router + cart + tweaks) ----------
const ShopCtx = createContext(null);
const useShop = () => useContext(ShopCtx);

function loadCart() {
  try { return JSON.parse(localStorage.getItem("dg-cart") || "[]"); } catch (e) { return []; }
}

function useShopState() {
  const [view, setViewRaw] = useState("home"); // home | product | cart | checkout
  const [cart, setCart] = useState(loadCart);
  const [drawer, setDrawer] = useState(false);
  const [toast, setToast] = useState(null);

  useEffect(() => { localStorage.setItem("dg-cart", JSON.stringify(cart)); }, [cart]);

  const navigate = useCallback((v) => {
    setViewRaw(v);
    setDrawer(false);
    requestAnimationFrame(() => window.scrollTo({ top: 0, behavior: "instant" in window ? "instant" : "auto" }));
  }, []);

  const addToCart = useCallback((item) => {
    setCart((c) => {
      const idx = c.findIndex((x) => x.color === item.color && x.size === item.size);
      if (idx >= 0) {
        const next = c.slice();
        next[idx] = { ...next[idx], qty: next[idx].qty + item.qty };
        return next;
      }
      return [...c, item];
    });
    setDrawer(true);
    setToast({ title: "Added to the bag", msg: `${PRODUCT.name} · ${item.colorName} · ${item.size}` });
    setTimeout(() => setToast(null), 2600);
  }, []);

  const updateQty = useCallback((i, q) => {
    setCart((c) => c.map((x, idx) => (idx === i ? { ...x, qty: Math.max(1, q) } : x)));
  }, []);
  const removeItem = useCallback((i) => setCart((c) => c.filter((_, idx) => idx !== i)), []);
  const clearCart = useCallback(() => setCart([]), []);

  const count = cart.reduce((s, x) => s + x.qty, 0);
  const subtotal = cart.reduce((s, x) => s + x.qty * x.price, 0);

  return { view, navigate, cart, addToCart, updateQty, removeItem, clearCart, count, subtotal,
    drawer, setDrawer, toast };
}

// ---------- Scroll reveal (rect poll; immune to missing scroll events) ----------
function Reveal({ children, delay = 0, rot = -2, as = "div", className = "", style = {}, threshold = 0.15 }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (seen) return;
    const el = ref.current;
    if (!el) return;
    const vh = () => window.innerHeight || document.documentElement.clientHeight;
    const check = () => {
      const r = el.getBoundingClientRect();
      if (r.top < vh() * 0.92 && r.bottom > 0) { setSeen(true); return true; }
      return false;
    };
    if (check()) return;
    const stop = () => { clearInterval(id); window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); };
    const onScroll = () => { if (check()) stop(); };
    const id = setInterval(() => { if (check()) stop(); }, 180);
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return stop;
  }, [seen]);
  const Tag = as;
  return (
    <Tag ref={ref} className={`reveal ${seen ? "in" : ""} ${className}`}
      style={{ "--rev-delay": delay + "ms", "--rev-rot": rot + "deg", ...style }}>
      {children}
    </Tag>
  );
}

// ---------- Parallax (direct DOM transform, no re-render) ----------
function useParallax(speed = 0.2, axis = "y", base = 0) {
  const ref = useRef(null);
  useEffect(() => {
    let raf = 0;
    const apply = () => {
      raf = 0;
      const m = window.__dgMotion ?? 1;
      const el = ref.current;
      if (!el) return;
      const rect = el.parentElement ? el.parentElement.getBoundingClientRect() : el.getBoundingClientRect();
      const center = rect.top + rect.height / 2 - window.innerHeight / 2;
      const d = -center * speed * m;
      el.style.transform = axis === "y"
        ? `translate3d(0, ${base + d}px, 0)`
        : `translate3d(${base + d}px, 0, 0)`;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(apply); };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    apply();
    return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); };
  }, [speed, axis, base]);
  return ref;
}

// ---------- Illustration ----------
function Illu({ src, alt = "", className = "", style = {} }) {
  return <img src={src} alt={alt} draggable={false} className={className}
    style={{ display: "block", userSelect: "none", pointerEvents: "none", ...style }} />;
}

// ---------- Vinyl record ----------
function Vinyl({ size = 240, spin = true, className = "", style = {} }) {
  return (
    <div className={`vinyl ${spin ? "spin-slow" : ""} ${className}`}
      style={{ width: size, height: size, ...style }}>
      <span className="label-dot" />
    </div>
  );
}

// ---------- Marquee ----------
function Marquee({ words, dur = 30, rev = false, bg = "var(--ink-900)", color = "var(--paper)",
  dot = "var(--pink-400)", border = true, height = 64, fontSize = "1.35rem" }) {
  const row = (
    <div className="marquee" style={{ "--mq-dur": dur + "s" }}>
      {[0, 1].map((copy) => (
        <div key={copy} style={{ display: "flex", alignItems: "center" }}>
          {words.map((w, i) => (
            <div key={i} style={{ display: "flex", alignItems: "center", flexShrink: 0 }}>
              <span style={{ fontFamily: "var(--font-heading)", fontWeight: 800, fontSize,
                letterSpacing: "0.02em", textTransform: "uppercase", padding: "0 22px", whiteSpace: "nowrap" }}>{w}</span>
              <span style={{ width: 14, height: 14, borderRadius: "50%", background: dot,
                border: "2px solid", borderColor: color === "var(--paper)" ? "rgba(255,255,255,0.5)" : "var(--ink-900)", flexShrink: 0 }} />
            </div>
          ))}
        </div>
      ))}
    </div>
  );
  return (
    <div className={`marquee-row ${rev ? "rev-wrap" : ""}`} style={{
      overflow: "hidden", background: bg, color, height, display: "flex", alignItems: "center",
      borderTop: border ? "3px solid var(--ink-900)" : "none",
      borderBottom: border ? "3px solid var(--ink-900)" : "none",
    }}>
      <div className={rev ? "marquee-flip" : ""} style={rev ? { transform: "scaleX(-1)" } : {}}>{row}</div>
    </div>
  );
}

// ---------- Cursor-reactive tee panel ----------
function TeeFrame({ colorKey = "white", slotId = "tee-main", interactive = true,
  height = 540, badge = "FRONT PRINT", rounded = "var(--radius-lg)", fit = "contain", style = {} }) {
  const wrapRef = useRef(null);
  const tiltRef = useRef(null);
  const color = PRODUCT.colors.find((c) => c.key === colorKey) || PRODUCT.colors[0];
  const dark = colorKey === "ink" || colorKey === "teal";

  useEffect(() => {
    if (!interactive) return;
    const wrap = wrapRef.current, tilt = tiltRef.current;
    if (!wrap || !tilt) return;
    const onMove = (e) => {
      const m = window.__dgMotion ?? 1;
      const r = wrap.getBoundingClientRect();
      const px = (e.clientX - r.left) / r.width - 0.5;
      const py = (e.clientY - r.top) / r.height - 0.5;
      tilt.style.transform = `rotateY(${px * 16 * m}deg) rotateX(${-py * 16 * m}deg) translateZ(0)`;
    };
    const onLeave = () => { tilt.style.transform = "rotateY(0) rotateX(0)"; };
    wrap.addEventListener("mousemove", onMove);
    wrap.addEventListener("mouseleave", onLeave);
    return () => { wrap.removeEventListener("mousemove", onMove); wrap.removeEventListener("mouseleave", onLeave); };
  }, [interactive]);

  return (
    <div ref={wrapRef} className="tilt-wrap" style={{ width: "100%", ...style }}>
      <div ref={tiltRef} className="tilt" style={{
        position: "relative", borderRadius: rounded, border: "3px solid var(--ink-900)",
        background: color.bg, boxShadow: "var(--shadow-pop-lg)", height, overflow: "hidden",
      }}>
        {/* halo behind print */}
        <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", pointerEvents: "none" }}>
          <div style={{ width: "78%", aspectRatio: "1", borderRadius: "50%",
            background: dark ? "rgba(255,255,255,0.06)" : "var(--pink-50)", filter: "blur(2px)", opacity: 0.8 }} />
        </div>
        <image-slot id={slotId} src={PRODUCT.art} fit={fit} shape="rect"
          placeholder="Drop a product photo"
          style={{ position: "absolute", inset: fit === "contain" ? "8%" : 0, width: fit === "contain" ? "84%" : "100%", height: fit === "contain" ? "84%" : "100%" }}></image-slot>
        {badge && (
          <div style={{ position: "absolute", top: 16, left: 16, zIndex: 3 }}>
            <span style={{ fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: "0.6875rem",
              letterSpacing: "0.08em", textTransform: "uppercase", padding: "4px 11px",
              borderRadius: "var(--radius-pill)", border: "2px solid var(--ink-900)",
              background: "var(--paper)", color: "var(--ink-900)" }}>{badge}</span>
          </div>
        )}
        <div style={{ position: "absolute", bottom: 14, right: 16, zIndex: 3,
          fontFamily: "var(--font-mono)", fontSize: "0.6875rem", letterSpacing: "0.08em",
          color: dark ? "rgba(255,255,255,0.8)" : "var(--ink-400)" }}>{color.name.toUpperCase()}</div>
      </div>
    </div>
  );
}

// ---------- Nav ----------
function Nav() {
  const { navigate, count, setDrawer, view } = useShop();
  const [solid, setSolid] = useState(false);
  useEffect(() => {
    const onScroll = () => setSolid(window.scrollY > 24);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  const links = [
    { label: "The Drop", go: () => navigate("product") },
    { label: "Lookbook", go: () => { if (view !== "home") navigate("home"); setTimeout(() => document.getElementById("lookbook")?.scrollIntoView?.({ behavior: "smooth" }), 80); } },
    { label: "The Crew", go: () => { if (view !== "home") navigate("home"); setTimeout(() => document.getElementById("story")?.scrollIntoView?.({ behavior: "smooth" }), 80); } },
  ];
  return (
    <header style={{
      position: "sticky", top: 0, zIndex: 60,
      background: solid ? "rgba(255,255,255,0.92)" : "transparent",
      backdropFilter: solid ? "saturate(1.2) blur(6px)" : "none",
      borderBottom: solid ? "3px solid var(--ink-900)" : "3px solid transparent",
      transition: "background .25s, border-color .25s",
    }}>
      <div className="wrap" style={{ height: 78, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 18 }}>
        <button onClick={() => navigate("home")} aria-label="Disco Gringo home"
          style={{ background: "none", border: "none", cursor: "pointer", padding: 0, display: "flex", alignItems: "center" }}>
          <img src="assets/wordmark.png" alt="Disco Gringo" style={{ height: 50, display: "block" }} draggable={false} />
        </button>
        <nav style={{ display: "flex", alignItems: "center", gap: 26 }} className="dg-navwrap">
          {links.map((l) => (
            <button key={l.label} className="dg-navlink" onClick={l.go}>{l.label}</button>
          ))}
          <button onClick={() => setDrawer(true)} aria-label="Open bag"
            style={{ position: "relative", width: 46, height: 46, borderRadius: "50%",
              border: "3px solid var(--ink-900)", background: "var(--pink-400)", cursor: "pointer",
              display: "inline-flex", alignItems: "center", justifyContent: "center",
              boxShadow: "var(--shadow-pop-sm)", transition: "transform var(--dur-fast) var(--ease-pop)" }}
            onMouseDown={(e) => (e.currentTarget.style.transform = "translate(2px,2px)")}
            onMouseUp={(e) => (e.currentTarget.style.transform = "")}
            onMouseLeave={(e) => (e.currentTarget.style.transform = "")}>
            <Icon name="shopping-bag" size={20} />
            {count > 0 && (
              <span style={{ position: "absolute", top: -8, right: -8, minWidth: 22, height: 22, padding: "0 5px",
                borderRadius: 11, background: "var(--teal-400)", color: "#fff", border: "2px solid var(--ink-900)",
                fontFamily: "var(--font-mono)", fontWeight: 700, fontSize: "0.7rem",
                display: "inline-flex", alignItems: "center", justifyContent: "center" }}>{count}</span>
            )}
          </button>
        </nav>
      </div>
    </header>
  );
}

// ---------- Footer ----------
function Footer() {
  const { navigate } = useShop();
  const [email, setEmail] = useState("");
  const [done, setDone] = useState(false);
  const { Button, Input } = window.DiscoGringoDesignSystem_9ed3f7;
  return (
    <footer style={{ background: "var(--ink-900)", color: "var(--paper)", borderTop: "3px solid var(--ink-900)", overflow: "hidden" }}>
      <div className="wrap" style={{ padding: "72px 32px 36px" }}>
        <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 48, alignItems: "start", flexWrap: "wrap" }} className="footer-grid">
          <div>
            <div className="sticker thin" style={{ fontSize: "clamp(2.4rem,6vw,4.2rem)" }}>GET ON<br />THE LIST</div>
            <p style={{ fontFamily: "var(--font-body)", fontSize: "1.05rem", maxWidth: 380, color: "rgba(255,255,255,0.78)", marginTop: 14 }}>
              We only message about drops. The plane's loading — don't miss the next one.
            </p>
            <div style={{ display: "flex", gap: 10, marginTop: 18, maxWidth: 440, flexWrap: "wrap" }}>
              <div style={{ flex: "1 1 220px" }}>
                <Input placeholder="you@party.com" value={email} onChange={(e) => setEmail(e.target.value)} />
              </div>
              <Button variant="primary" size="lg" onClick={() => { if (email) { setDone(true); setEmail(""); } }}>
                {done ? "You're in!" : "Get on the list"}
              </Button>
            </div>
          </div>
          <div style={{ display: "flex", gap: 56, flexWrap: "wrap" }}>
            <FooterCol title="Shop" links={[["The WAVE AIR tee", () => navigate("product")], ["Your bag", () => navigate("cart")]]} />
            <FooterCol title="Crew" links={[["Our story", () => navigate("home")], ["Sizing", () => navigate("product")], ["Shipping", () => navigate("product")]]} />
          </div>
        </div>
        <div style={{ marginTop: 64, borderTop: "2px solid rgba(255,255,255,0.18)", paddingTop: 22,
          display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 14 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: "0.8rem", letterSpacing: "0.08em", color: "rgba(255,255,255,0.6)" }}>
            © 2026 DISCO GRINGO · WAVE AIR · PALMAS BEACH
          </span>
          <div style={{ display: "flex", gap: 16 }}>
            {["instagram", "youtube", "music"].map((n) => (
              <span key={n} style={{ width: 40, height: 40, borderRadius: "50%", border: "2px solid rgba(255,255,255,0.4)",
                display: "inline-flex", alignItems: "center", justifyContent: "center", color: "#fff" }}>
                <Icon name={n} size={18} />
              </span>
            ))}
          </div>
        </div>
      </div>
      <div className="sticker" aria-hidden="true" style={{ fontSize: "clamp(3rem,16vw,11rem)", textAlign: "center",
        whiteSpace: "nowrap", margin: "0 0 -2.2vw", opacity: 0.96, lineHeight: 0.8 }}>DISCO GRINGO</div>
    </footer>
  );
}
function FooterCol({ title, links }) {
  return (
    <div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: "0.75rem", letterSpacing: "0.12em",
        textTransform: "uppercase", color: "var(--teal-300)", marginBottom: 14 }}>{title}</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 11 }}>
        {links.map(([label, go]) => (
          <button key={label} onClick={go} style={{ background: "none", border: "none", textAlign: "left", padding: 0,
            cursor: "pointer", fontFamily: "var(--font-heading)", fontWeight: 700, fontSize: "1.0625rem", color: "var(--paper)" }}>{label}</button>
        ))}
      </div>
    </div>
  );
}

window.DGShop = {
  Icon, PRODUCT, money, ShopCtx, useShop, useShopState,
  Reveal, useParallax, Illu, Vinyl, Marquee, TeeFrame, Nav, Footer,
};
