/* app.jsx — top-level app.
 * Routes:
 *   #admin           → admin portal (password-gated)
 *   #/              → invitation site, code-gated
 * State:
 *   - activeCode in sessionStorage (lost on tab close, by design)
 *   - lastCode in localStorage so a returning device prefills
 * Tweaks (cycle from the toolbar):
 *   palette         · warm | sage | rose | charcoal
 *   codeEntry       · card | inline
 *   rsvpVariant     · onepage | stepper
 */

const { useState: useStateApp, useEffect: useEffectApp } = React;

const SITE = {
  brideFirst: "Alex",
  brideLast: "Moderate",
  groomFirst: "Rhyan",
  groomLast: "Bushi",
  dateLong: "26 · August · 2027",
  dateIso: "2027-08-26T13:00:00",
  paypalUrl: "https://www.paypal.com/donate/?hosted_button_id=XWPSK7S8BSVZ4",
  paypalLabel: "Honeymoon pool",
  ceremony: {
    name: "Church of the Holy Name",
    addr: "Jesmond, Newcastle upon Tyne",
    maps: "https://maps.google.com/?q=Church+of+the+Holy+Name+Jesmond+Newcastle"
  },
  reception: {
    name: "Wylam Brewery",
    addr: "Palace of Arts, Exhibition Park, Newcastle upon Tyne NE2 4PZ",
    maps: "https://maps.google.com/?q=Wylam+Brewery+Newcastle"
  },
  schedule: [
    { time: "12:30 pm", title: "Arrivals at the church",   desc: "Take a seat in the nave — service begins on the hour." },
    { time: "1:00 pm",  title: "Ceremony",                  desc: "The marriage of Rhyan and Alex at the Church of the Holy Name." },
    { time: "2:15 pm",  title: "Drive to Wylam",            desc: "A short fifteen-minute journey to Exhibition Park." },
    { time: "3:30 pm",  title: "Reception arrivals",        desc: "Welcome drinks on the lawn, weather permitting." },
    { time: "5:00 pm",  title: "Wedding breakfast",         desc: "A long table dinner in the Palace of Arts." },
    { time: "7:30 pm",  title: "Speeches & cake",           desc: "Sit tight — there will be tissues." },
    { time: "8:30 pm",  title: "First dance & evening",     desc: "Dance floor opens. Late-night bites at half past ten." },
    { time: "12:30 am", title: "Carriages",                 desc: "Until next time. Safe journeys home." }
  ],
  story: [
    { when: "School days",         title: "We met at school",          body: "Same classrooms, same corridors — the start of everything, even if we didn't quite know it yet." },
    { when: "Age 15",              title: "Our first proper date",     body: "McDonald\u2019s in the Asda at Benton. Not the most romantic backdrop on paper, but it turns out it was perfect." },
    { when: "20 November 2017",    title: "We got together",           body: "The day everything changed — the one we mark each year, and the reason we\u2019re here today." },
    { when: "August 2021",         title: "Moving in together",        body: "Our first place, our first sofa, and far too many candles. The beginning of building a life under one roof." },
    { when: "5 April 2025",        title: "The proposal",              body: "A very nervous question and a very happy yes. The full story is one for the speeches." },
    { when: "26 August 2027",      title: "The wedding",                body: "Which brings us, joyfully, to you." }
  ],
  faq: [
    { q: "Are children welcome?",
      a: "We adore the little ones in our lives, but our wedding will be an adults-only celebration so everyone can let loose. We hope you'll see this as an excuse for a night out." },
    { q: "Is there parking at Wylam?",
      a: "Yes — there's a free car park on-site at Exhibition Park. The brewery is also a short cab from Central Station and Haymarket metro." },
    { q: "Can I take photos?",
      a: "Please do — and please share them. There's an upload spot lower on this page so we can collect them after the day." }
  ]
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "warm",
  "codeEntry": "card",
  "rsvpVariant": "onepage"
}/*EDITMODE-END*/;

const PALETTE_LABELS = {
  warm: "Warm Cream",
  sage: "Sage & Cream",
  rose: "Dusty Rose",
  charcoal: "Charcoal"
};

// ── Routing helpers (hash-based; production would map #admin → /admin) ────
function useHashRoute() {
  const [hash, setHash] = useStateApp(() => window.location.hash || "#/");
  useEffectApp(() => {
    function onHash() { setHash(window.location.hash || "#/"); }
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  return hash;
}

// ── Main site (after a guest has unlocked it) ─────────────────────────────
function MainSite({ guest, onUpdateGuest, onLogout, rsvpVariant }) {
  return (
    <div>
      <div className="topbar">
        <div className="topbar-inner">
          <div className="topbar-title">{SITE.groomFirst} & {SITE.brideFirst}</div>
          <button className="topbar-logout" onClick={onLogout}>Sign out</button>
        </div>
      </div>

      <CoupleIntro site={SITE} />
      <CountdownBlock site={SITE} />
      <ScheduleBlock site={SITE} />
      <VenueBlock site={SITE} />
      <StayBlock />
      <GiftBlock site={SITE} />
      <StoryBlock site={SITE} />
      <GalleryBlock />
      <DressBlock />
      <FaqBlock site={SITE} />
      <RsvpBlock guest={guest} variant={rsvpVariant} onUpdate={onUpdateGuest} />
      <PhotoUploadBlock guest={guest} />
      <SignOff site={SITE} />
    </div>
  );
}

// ── Code-gated entry ─────────────────────────────────────────────────────
const INTERSTITIAL_MS = 2400;

function Interstitial({ label, name, sub, monogram }) {
  return (
    <div className="interstitial">
      <div className="interstitial-inner">
        {monogram ? (
          <div className="i-monogram serif">
            {monogram.split("").map((ch, i) => (
              i === 1 ? <span key={i} className="sep">✦</span> : <span key={i}>{ch}</span>
            ))}
          </div>
        ) : null}
        <div className="i-rule"><span className="dot"></span></div>
        <div className="i-label">{label}</div>
        <div className="i-name serif">{name}</div>
        {sub ? <div className="i-sub">{sub}</div> : null}
      </div>
    </div>
  );
}

function InvitationApp({ codeEntry, rsvpVariant }) {
  const [guest, setGuest] = useStateApp(null);
  const [phase, setPhase] = useStateApp("locked"); // locked | intro | rsvp | handoff | site
  const [msg, setMsg] = useStateApp("");
  const [msgOk, setMsgOk] = useStateApp(false);
  const [busy, setBusy] = useStateApp(false);

  // Restore session on load — skip interstitial on cold restore
  useEffectApp(() => {
    const active = weddingAPI.getActiveCode();
    if (active) {
      weddingAPI.validateCode(active).then((g) => {
        if (g) {
          setGuest(g);
          setPhase(g.status === "pending" ? "rsvp" : "site");
        } else {
          weddingAPI.setActiveCode(null);
        }
      });
    }
  }, []);

  async function handleSubmit(code) {
    if (busy) return;
    if (!code) { setMsg("Please enter your invitation code"); setMsgOk(false); return; }
    setBusy(true);
    const g = await weddingAPI.validateCode(code);
    setBusy(false);
    if (!g) {
      setMsg("We don't recognise that code — try again?");
      setMsgOk(false);
      return;
    }
    weddingAPI.setActiveCode(g.code);
    weddingAPI.rememberCode(g.code);
    setMsg("");
    setGuest(g);
    setPhase("intro");
    setTimeout(() => {
      setPhase(g.status === "pending" ? "rsvp" : "site");
      window.scrollTo({ top: 0 });
    }, INTERSTITIAL_MS);
  }

  function handleLogout() {
    weddingAPI.setActiveCode(null);
    setGuest(null);
    setPhase("locked");
    setMsg("");
    window.scrollTo({ top: 0 });
  }

  function handleRsvpComplete(updated) {
    setGuest(updated);
    setPhase("handoff");
    setTimeout(() => {
      setPhase("site");
      window.scrollTo({ top: 0 });
    }, INTERSTITIAL_MS);
  }

  // Decide which name to show on the interstitial — family vs solo
  function displayName(g) {
    if (!g) return "";
    if (g.members && g.members.length) return g.name;       // "The Carter Family"
    return g.name.split(" ")[0];                             // first name
  }

  // ── Render by phase ────────────────────────────────────────────
  if (phase === "site" && guest) {
    return (
      <MainSite
        guest={guest}
        onUpdateGuest={(g) => setGuest(g)}
        onLogout={handleLogout}
        rsvpVariant={rsvpVariant}
      />
    );
  }

  if (phase === "intro" && guest) {
    const isPending = guest.status === "pending";
    return (
      <React.Fragment>
        {/* Render the destination underneath so the fade reveals it cleanly */}
        <div style={{ position: "fixed", inset: 0, overflow: "hidden", pointerEvents: "none" }}>
          {isPending
            ? <RsvpGate guest={guest} variant={rsvpVariant} site={SITE} onComplete={() => {}} onSignOut={() => {}} />
            : <MainSiteShell />}
        </div>
        <Interstitial
          label="Welcome"
          name={displayName(guest)}
          sub={isPending ? "Let's get you registered" : SITE.dateLong}
        />
      </React.Fragment>
    );
  }

  if (phase === "rsvp" && guest) {
    return (
      <RsvpGate
        guest={guest}
        variant={rsvpVariant}
        site={SITE}
        onComplete={handleRsvpComplete}
        onSignOut={handleLogout}
      />
    );
  }

  if (phase === "handoff" && guest) {
    return (
      <React.Fragment>
        {/* Site loads underneath so the curtain pulls away into the real page */}
        <div style={{ position: "fixed", inset: 0, overflow: "hidden", pointerEvents: "none" }}>
          <MainSiteShell />
        </div>
        <Interstitial
          monogram={`${SITE.groomFirst[0]}*${SITE.brideFirst[0]}`}
          label="Thank you"
          name={displayName(guest)}
          sub={SITE.dateLong}
        />
      </React.Fragment>
    );
  }

  return (
    <Hero
      site={SITE}
      variant={codeEntry === "inline" ? "inline" : "card"}
      onSubmit={handleSubmit}
      message={msg}
      messageOk={msgOk}
    />
  );
}

// Stub used as a subtle background blur behind interstitials so the next view
// is half-visible during the fade. Renders nothing if we don't have a guest.
function MainSiteShell() {
  return (
    <div style={{
      position: "absolute", inset: 0,
      background: "var(--bg)",
      opacity: 1
    }}></div>
  );
}

// ── Demo codes helper ─────────────────────────────────────────────────────
function DemoHint() {
  const [hidden, setHidden] = useStateApp(false);
  if (hidden) return null;
  return (
    <div style={{
      position: "fixed",
      bottom: 16,
      left: 16,
      zIndex: 100,
      maxWidth: 280,
      padding: "14px 16px",
      background: "rgba(20, 18, 14, 0.78)",
      backdropFilter: "blur(12px)",
      color: "#fff",
      fontSize: 11.5,
      lineHeight: 1.55,
      borderRadius: 4,
      border: "1px solid rgba(255,255,255,0.15)"
    }}>
      <div style={{ fontSize: 9.5, letterSpacing: "0.32em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)", marginBottom: 6 }}>
        Demo
      </div>
      <div style={{ marginBottom: 6 }}>Try a code:</div>
      <div style={{ marginBottom: 6, paddingLeft: 8 }}>
        <b style={{ letterSpacing: "0.18em" }}>ORCHID</b> · first-time, RSVP intake<br/>
        <b style={{ letterSpacing: "0.18em" }}>WILLOW</b> · family of four (2 children)<br/>
        <b style={{ letterSpacing: "0.18em" }}>LAUREL</b> · already registered<br/>
        <b style={{ letterSpacing: "0.18em" }}>MYRTLE</b> · declined
      </div>
      <div style={{ marginBottom: 8 }}>Admin: open <a href="#admin" style={{ borderBottom: "1px solid rgba(255,255,255,0.5)" }}>#admin</a>.</div>
      <button onClick={() => setHidden(true)} style={{
        background: "transparent", border: 0, color: "rgba(255,255,255,0.6)",
        fontSize: 10, letterSpacing: "0.22em", textTransform: "uppercase", cursor: "pointer", padding: 0
      }}>Dismiss</button>
    </div>
  );
}

// ── App root ─────────────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const hash = useHashRoute();

  // Apply palette via data attribute on <html>
  useEffectApp(() => {
    document.documentElement.setAttribute("data-palette", t.palette);
  }, [t.palette]);

  const isAdmin = hash.startsWith("#admin");

  return (
    <React.Fragment>
      {isAdmin
        ? <AdminPortal />
        : <InvitationApp codeEntry={t.codeEntry} rsvpVariant={t.rsvpVariant} />
      }
      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakSelect
          label="Palette"
          value={t.palette}
          options={[
            { value: "warm",     label: PALETTE_LABELS.warm },
            { value: "sage",     label: PALETTE_LABELS.sage },
            { value: "rose",     label: PALETTE_LABELS.rose },
            { value: "charcoal", label: PALETTE_LABELS.charcoal }
          ]}
          onChange={(v) => setTweak("palette", v)}
        />
        <TweakSection label="Code-entry style" />
        <TweakRadio
          label="Hero entry"
          value={t.codeEntry}
          options={[
            { value: "card",   label: "Centred card" },
            { value: "inline", label: "Inline pill" }
          ]}
          onChange={(v) => setTweak("codeEntry", v)}
        />
        <TweakSection label="RSVP form" />
        <TweakRadio
          label="Layout"
          value={t.rsvpVariant}
          options={[
            { value: "onepage", label: "One page" },
            { value: "stepper", label: "Stepper" }
          ]}
          onChange={(v) => setTweak("rsvpVariant", v)}
        />
        <TweakSection label="Admin" />
        <TweakButton label="Open admin portal" onClick={() => { window.location.hash = "#admin"; }} />
        <TweakButton label="Back to invitation" secondary onClick={() => { window.location.hash = "#/"; }} />
        <TweakSection label="Demo data" />
        <TweakButton label="Reset all data" secondary onClick={() => {
          if (confirm("Wipe all guests/photos and reload?")) {
            weddingAPI._resetAll();
            location.reload();
          }
        }} />
      </TweaksPanel>
    </React.Fragment>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
