/* ============== NOM NOM TAIWAN — interactions ============== */

const { useState, useEffect } = React;

// ---------- Tweaks defaults (editable in repo) ----------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "magenta",
  "tone": "refined",
  "photo": "polaroid",
  "showStickers": true
}/*EDITMODE-END*/;

const PALETTES = {
  magenta: { brand: "#E91E8C", deep: "#B8156D", paper: "#F4EFE6", warm: "#EDE5D4", ink: "#0E0A0A" },
  orange:  { brand: "#E8763A", deep: "#B8541A", paper: "#F4EFE6", warm: "#EDE5D4", ink: "#0E0A0A" },
  jade:    { brand: "#0E8C6A", deep: "#0A6A52", paper: "#F1EEE2", warm: "#E8E1CD", ink: "#0E0A0A" },
  ink:     { brand: "#E91E8C", deep: "#B8156D", paper: "#0E0A0A", warm: "#1A1413", ink: "#F4EFE6" },
};

function applyPalette(key) {
  const p = PALETTES[key] || PALETTES.magenta;
  const root = document.documentElement;
  root.style.setProperty("--magenta", p.brand);
  root.style.setProperty("--magenta-deep", p.deep);
  root.style.setProperty("--cream", p.paper);
  root.style.setProperty("--cream-warm", p.warm);
  root.style.setProperty("--ink", p.ink);
}

const PLAYFUL_COPY = {
  hero_tagline: "BIG fryer. LITTLE truck. INFINITE chicken. 卡加利最酥的鹹酥雞 — come get crunchy with us.",
  story_lede: "Two cousins. ONE fryer. A grandma recipe we straight-up smuggled in a Tupperware. (Sorry, customs.)",
  signature: "CHICKEN, BABY",
  next_stop_addr: "Look for the magenta truck — you literally cannot miss it. Honk twice for free napkins."
};
const REFINED_COPY = {
  hero_tagline: document.querySelector(".hero-tagline")?.innerHTML || "",
  story_lede: document.querySelector(".story-text .lede")?.innerHTML || "",
  next_stop_addr: document.querySelector(".next-stop .addr")?.innerHTML || ""
};

function applyTone(tone) {
  document.body.setAttribute("data-tone", tone);
  if (tone === "playful") {
    const t = document.querySelector(".hero-tagline");
    if (t) t.innerHTML = PLAYFUL_COPY.hero_tagline;
    const l = document.querySelector(".story-text .lede");
    if (l) l.innerHTML = "Two cousins. <em>One fryer.</em> A grandma recipe we straight-up smuggled in a Tupperware. (Sorry, customs.)";
    const a = document.querySelector(".next-stop .addr");
    if (a) a.textContent = PLAYFUL_COPY.next_stop_addr;
  } else {
    const t = document.querySelector(".hero-tagline");
    if (t && REFINED_COPY.hero_tagline) t.innerHTML = REFINED_COPY.hero_tagline;
    const l = document.querySelector(".story-text .lede");
    if (l && REFINED_COPY.story_lede) l.innerHTML = REFINED_COPY.story_lede;
    const a = document.querySelector(".next-stop .addr");
    if (a && REFINED_COPY.next_stop_addr) a.textContent = "Downtown Calgary · Outside the courthouse · Look for the magenta truck.";
  }
}

function applyPhoto(mode) {
  document.body.setAttribute("data-photo", mode);
}

// ---------- Tweaks panel UI ----------
function TweaksApp() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  useEffect(() => { applyPalette(t.palette); }, [t.palette]);
  useEffect(() => { applyTone(t.tone); }, [t.tone]);
  useEffect(() => { applyPhoto(t.photo); }, [t.photo]);

  return (
    <TweaksPanel title="Tweaks · NOM NOM">
      <TweakSection title="Brand color">
        <TweakColor
          value={t.palette === "magenta" ? "#E91E8C" : t.palette === "orange" ? "#E8763A" : t.palette === "jade" ? "#0E8C6A" : "#E91E8C"}
          onChange={(c) => {
            const map = { "#E91E8C": "magenta", "#E8763A": "orange", "#0E8C6A": "jade", "#0E0A0A": "ink" };
            setTweak("palette", map[c] || "magenta");
          }}
          options={["#E91E8C", "#E8763A", "#0E8C6A", "#0E0A0A"]}
          label="Palette"
        />
      </TweakSection>

      <TweakSection title="Photo treatment">
        <TweakRadio
          value={t.photo}
          onChange={(v) => setTweak("photo", v)}
          options={[
            { value: "polaroid", label: "Polaroid" },
            { value: "grid",     label: "Clean grid" },
            { value: "bleed",    label: "Full bleed" },
          ]}
          label="Style"
        />
      </TweakSection>

      <TweakSection title="Copy tone">
        <TweakRadio
          value={t.tone}
          onChange={(v) => setTweak("tone", v)}
          options={[
            { value: "refined", label: "Refined" },
            { value: "playful", label: "Playful" },
          ]}
          label="Voice"
        />
      </TweakSection>
    </TweaksPanel>
  );
}

ReactDOM.createRoot(document.getElementById("tweaks-root")).render(<TweaksApp />);

// ---------- Dynamic content (menu / schedule) ----------
async function loadContent() {
  let content = null;
  try {
    const r = await fetch("/api/content", { cache: "no-store" });
    if (r.ok) content = await r.json();
  } catch {}
  if (!content || !Array.isArray(content.menu)) {
    try {
      const r = await fetch("content.json", { cache: "no-cache" });
      if (r.ok) content = await r.json();
    } catch {}
  }
  return content || { menu: [], schedule: [] };
}

function parseEm(text) {
  return String(text).split(/(\*[^*]+\*)/g).map((p, i) =>
    p.startsWith("*") && p.endsWith("*") && p.length > 2
      ? <em key={i}>{p.slice(1, -1)}</em>
      : <React.Fragment key={i}>{p}</React.Fragment>
  );
}
function renderName(name) {
  return String(name).split(/\\n|\n/).map((line, i, arr) => (
    <React.Fragment key={i}>
      {parseEm(line)}
      {i < arr.length - 1 && <br/>}
    </React.Fragment>
  ));
}

function MenuItem({ item }) {
  const stars = Math.max(0, Math.min(5, Number(item.stars) || 0));
  const lines = item.imageLines || [];
  return (
    <article className={"menu-item " + (item.size || "col-4") + " reveal"}>
      <div className="number">
        <span>№ {item.num} — {item.category}</span>
        <span>{"★".repeat(stars)}{"☆".repeat(5 - stars)}</span>
      </div>
      <div className="img-wrap" style={{ transform: `rotate(${item.rotation || 0}deg)` }}>
        <div className="polaroid p-lg" style={{ width: "100%" }}>
          <div className="photo">
            {item.photoUrl ? (
              <img src={item.photoUrl} alt={item.name.replace(/\*/g, '')} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
            ) : (
              <div className={"placeholder ph-" + (item.image || "chicken")}>
                <span>{lines.map((l, i) => (
                  <React.Fragment key={i}>{i > 0 && <br/>}{l}</React.Fragment>
                ))}</span>
              </div>
            )}
          </div>
          <div className="caption">
            <span>{item.imageCaption || ""}</span>
            <span>{item.price}</span>
          </div>
        </div>
      </div>
      <span className="price">{item.price}</span>
      <h3>{renderName(item.name)}</h3>
      <div className="tc-name">{item.nameTC}</div>
      <p className="desc">{item.description}</p>
    </article>
  );
}

function ScheduleRow({ row }) {
  return (
    <div className={"schedule-row" + (row.isNext ? " next" : "")}
         style={row.dim ? { opacity: 0.4 } : undefined}>
      <span className="day">{row.day}</span>
      <span className="place">{row.place}</span>
      <span className="addr">{row.addr}</span>
      <span className="time">{row.time}</span>
      <span className="status">{row.status}</span>
    </div>
  );
}

// ---------- GSAP scroll animations ----------
function initGSAP() {
  if (!window.gsap) return;
  gsap.registerPlugin(ScrollTrigger);

  // Hero title words rise in
  gsap.from(".hero-title .word", {
    y: 120,
    opacity: 0,
    duration: 1.1,
    stagger: 0.08,
    ease: "power3.out",
  });
  gsap.from(".hero-tc", {
    scale: 0.4, opacity: 0, duration: 1.2, stagger: 0.1, ease: "back.out(1.7)", delay: 0.3
  });
  gsap.from(".hero-poly", {
    y: 60, opacity: 0, rotate: 0, duration: 1.2, stagger: 0.15, ease: "power2.out", delay: 0.6,
    clearProps: "transform"
  });
  gsap.from(".hero-eyebrow > div", { opacity: 0, y: -20, duration: 0.8, stagger: 0.1 });
  gsap.from(".hero-bottom > *", { opacity: 0, y: 30, duration: 0.9, stagger: 0.15, delay: 0.8 });

  // Section heads
  gsap.utils.toArray(".section-head").forEach((head) => {
    gsap.from(head.querySelectorAll(".num, h2, .tc-mark"), {
      scrollTrigger: { trigger: head, start: "top 80%" },
      y: 40, opacity: 0, duration: 0.9, stagger: 0.1, ease: "power3.out"
    });
  });

  // Story polaroids
  gsap.utils.toArray(".story-poly-stack .polaroid").forEach((p, i) => {
    gsap.from(p, {
      scrollTrigger: { trigger: ".story-poly-stack", start: "top 80%" },
      y: 80, opacity: 0, scale: 0.85,
      duration: 1.1, delay: i * 0.15, ease: "power3.out",
      clearProps: "scale"
    });
  });

  // Stats count
  gsap.utils.toArray(".story-stats .stat").forEach((s, i) => {
    gsap.from(s, {
      scrollTrigger: { trigger: ".story-stats", start: "top 85%" },
      y: 30, opacity: 0, duration: 0.7, delay: i * 0.1
    });
  });

  // Find / map
  gsap.from(".next-stop", {
    scrollTrigger: { trigger: ".find-grid", start: "top 80%" },
    x: -60, opacity: 0, duration: 1.0, ease: "power3.out"
  });
  gsap.from(".map-card", {
    scrollTrigger: { trigger: ".find-grid", start: "top 80%" },
    x: 60, opacity: 0, duration: 1.0, ease: "power3.out"
  });
  // Footer big text parallax
  gsap.to(".footer .big", {
    scrollTrigger: { trigger: ".footer", start: "top 80%", end: "bottom bottom", scrub: 1 },
    x: -100,
  });
}

function animateContent() {
  if (!window.gsap) return;
  gsap.utils.toArray(".menu-item").forEach((item) => {
    gsap.from(item, {
      scrollTrigger: { trigger: item, start: "top 85%" },
      y: 80, opacity: 0, duration: 1.0, ease: "power3.out",
    });
  });
  gsap.from(".schedule-row", {
    scrollTrigger: { trigger: ".schedule", start: "top 80%" },
    x: -30, opacity: 0, duration: 0.6, stagger: 0.06,
  });
}

// Static-DOM animations fire as soon as the script runs (independent of /api/content fetch)
if (document.readyState === "complete" || document.readyState === "interactive") {
  initGSAP();
} else {
  document.addEventListener("DOMContentLoaded", initGSAP);
}

async function bootSite() {
  const content = await loadContent();

  const menuRoot = document.getElementById("menu-grid-root");
  if (menuRoot) {
    ReactDOM.createRoot(menuRoot).render(
      <>{(content.menu || []).map((m, i) => <MenuItem key={m.id || `m-${i}`} item={m} />)}</>
    );
  }

  const schedRoot = document.getElementById("schedule-root");
  if (schedRoot) {
    ReactDOM.createRoot(schedRoot).render(
      <>{(content.schedule || []).map((r, i) => <ScheduleRow key={r.id || `s-${i}`} row={r} />)}</>
    );
  }

  // Wait two frames for React to commit + paint, then animate dynamic content
  requestAnimationFrame(() => requestAnimationFrame(animateContent));
}
bootSite();

// ---------- Live countdown ----------
function tickCountdown() {
  const target = new Date();
  // Next stop "opens" 2h14m38s from initial load — drift down each second
  if (!window.__nomTarget) {
    window.__nomTarget = Date.now() + (2 * 3600 + 14 * 60 + 38) * 1000;
  }
  let diff = Math.max(0, window.__nomTarget - Date.now());
  const h = Math.floor(diff / 3600000); diff -= h * 3600000;
  const m = Math.floor(diff / 60000); diff -= m * 60000;
  const s = Math.floor(diff / 1000);
  const pad = (n) => String(n).padStart(2, "0");
  document.querySelectorAll('[data-ct="h"]').forEach(el => el.textContent = pad(h));
  document.querySelectorAll('[data-ct="m"]').forEach(el => el.textContent = pad(m));
  document.querySelectorAll('[data-ct="s"]').forEach(el => el.textContent = pad(s));
}
setInterval(tickCountdown, 1000);
tickCountdown();

// ---------- Map pin interactivity ----------
document.querySelectorAll(".map-pin").forEach((pin) => {
  // Flip label to the left side when pin is near the right edge of the map
  const leftPct = parseFloat(pin.style.left);
  if (!Number.isNaN(leftPct) && leftPct > 65) pin.classList.add("label-left");

  pin.addEventListener("click", () => {
    document.querySelectorAll(".map-pin").forEach(p => p.classList.remove("active"));
    pin.classList.add("active");
  });

  // Keyboard accessibility
  pin.setAttribute("role", "button");
  pin.setAttribute("tabindex", "0");
  pin.addEventListener("keydown", (e) => {
    if (e.key === "Enter" || e.key === " ") { e.preventDefault(); pin.click(); }
  });
});

// ---------- Header: scroll-aware bg + dark-section detection ----------
(function () {
  const header = document.querySelector(".site-header");
  if (!header) return;
  const darkSelectors = ".story, .footer, .marquee";

  function update() {
    header.classList.toggle("is-scrolled", window.scrollY > 24);

    // Sample point just below header midline
    const probeY = header.getBoundingClientRect().bottom - 6;
    let onDark = false;
    document.querySelectorAll(darkSelectors).forEach((s) => {
      const r = s.getBoundingClientRect();
      if (r.top <= probeY && r.bottom >= probeY) onDark = true;
    });
    header.classList.toggle("is-on-dark", onDark);
  }

  let ticking = false;
  window.addEventListener("scroll", () => {
    if (!ticking) {
      requestAnimationFrame(() => { update(); ticking = false; });
      ticking = true;
    }
  }, { passive: true });
  update();
})();

// ---------- In-page anchor smooth scroll (respects reduced motion) ----------
document.querySelectorAll('a[href^="#"]').forEach((a) => {
  a.addEventListener("click", (e) => {
    const id = a.getAttribute("href");
    if (!id || id === "#") return;
    const target = document.querySelector(id);
    if (!target) return;
    e.preventDefault();
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    target.scrollIntoView({ behavior: reduce ? "auto" : "smooth", block: "start" });
    history.replaceState(null, "", id);
  });
});
