// App.jsx — main orchestrator for the wedding site.
// Handles scroll-driven rotation of the library, the envelope reveal,
// the RSVP sheet, and the attire board overlay.

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

// PRODUCTION CONFIG —
// After you deploy the Apps Script as a Web App, paste its /exec URL into
// SHEET_ENDPOINT below. RSVPs will then post into the wedding spreadsheet
// and trigger the confirmation email automatically.
// You can also override at runtime by setting window.SHEET_ENDPOINT in
// index.html before App mounts.
const SHEET_ENDPOINT = "https://script.google.com/macros/s/AKfycbzrk-BAZ8XZ96h5YPo477wqNdukEi2lbUwDgqrr3ZzlHHBTr7MiqbxamXSnqWDjK_pqxw/exec";

const DEFAULT_TWEAKS = /*EDITMODE-BEGIN*/{
  "brideName": "Audrey",
  "groomName": "Nicholas",
  "weddingDate": "29 August 2026",
  "venueName": "State Library Victoria",
  "venueCity": "Melbourne",
  "sheetEndpoint": (typeof window !== 'undefined' && window.SHEET_ENDPOINT) || SHEET_ENDPOINT,
  "rotationTurns": 1,
  "accentColor": "#6b3508",
  "inkColor": "#281e0b"
} /*EDITMODE-END*/;

function useScrollProgress(ref) {
  const [data, setData] = React.useState({ progress: 0, top: 0, height: 1 });
  React.useEffect(() => {
    function update() {
      if (!ref.current) return;
      const el = ref.current;
      const rect = el.getBoundingClientRect();
      const total = el.offsetHeight - window.innerHeight;
      const scrolled = Math.max(0, Math.min(total, -rect.top));
      setData({ progress: total > 0 ? scrolled / total : 0, top: rect.top, height: el.offsetHeight });
    }
    update();
    window.addEventListener('scroll', update, { passive: true });
    window.addEventListener('resize', update);
    return () => {
      window.removeEventListener('scroll', update);
      window.removeEventListener('resize', update);
    };
  }, [ref]);
  return data;
}

function App() {
  const [tweaks, setTweaks] = React.useState(DEFAULT_TWEAKS);
  const [tweakMode, setTweakMode] = React.useState(false);
  const [rsvpOpen, setRsvpOpen] = React.useState(false);
  const [rsvpOrigin, setRsvpOrigin] = React.useState(null); // {x, y}
  const [rsvpUpdateToken, setRsvpUpdateToken] = React.useState(null); // base64-encoded email from update link
  const [attireOpen, setAttireOpen] = React.useState(false);
  const [detailsOpen, setDetailsOpen] = React.useState(false);
  const [hotelsOpen, setHotelsOpen] = React.useState(false);

  // Menu navigation — clicking any menu item from inside another overlay
  // should close the current one before opening the new one. Logo clicks
  // close everything (returns the guest to the homepage).
  function goHome() {
    setAttireOpen(false);
    setDetailsOpen(false);
    setHotelsOpen(false);
  }
  function goTo(target) {
    setAttireOpen(target === 'attire');
    setDetailsOpen(target === 'details');
    setHotelsOpen(target === 'hotels');
  }

  // Helper: open RSVP and remember where on the screen the click originated,
  // so the modal can reveal from that exact point (the envelope wax seal).
  function openRsvp(eventOrEl) {
    let x = window.innerWidth / 2;
    let y = window.innerHeight / 2;
    const el = eventOrEl && (eventOrEl.currentTarget || eventOrEl.target || eventOrEl);
    if (el && el.getBoundingClientRect) {
      const r = el.getBoundingClientRect();
      x = r.left + r.width / 2;
      y = r.top + r.height / 2;
    }
    setRsvpOrigin({ x, y });
    setRsvpOpen(true);
  }

  const heroRef = React.useRef(null);
  const { progress: heroProgress } = useScrollProgress(heroRef);

  // Apply tweak colors to root
  React.useEffect(() => {
    document.documentElement.style.setProperty('--gold', tweaks.accentColor);
    document.documentElement.style.setProperty('--ink', tweaks.inkColor);
  }, [tweaks.accentColor, tweaks.inkColor]);

  // Deep-link: ?rsvp=open opens the RSVP modal on page load. The confirmation
  // email links here so guests can update their response directly from the
  // inbox without hunting for the button. If `token` is also present, it's a
  // base64-encoded email from the confirmation email's "Update your response"
  // button — RSVPFlow uses it to skip name + email lookup and load previous
  // selections directly. (`email` is supported as an alias.)
  React.useEffect(() => {
    try {
      const params = new URLSearchParams(window.location.search);
      if (params.get('rsvp') === 'open') {
        setRsvpOpen(true);
        const token = params.get('token') || params.get('email');
        if (token) setRsvpUpdateToken(token);
        // Clean the URL so refreshing doesn't keep re-opening the modal
        const cleanUrl = window.location.pathname + window.location.hash;
        window.history.replaceState({}, '', cleanUrl);
      }
    } catch {}
  }, []);

  // Tweaks protocol
  React.useEffect(() => {
    function onMsg(e) {
      const d = e.data;
      if (!d) return;
      if (d.type === '__activate_edit_mode') setTweakMode(true);
      if (d.type === '__deactivate_edit_mode') setTweakMode(false);
    }
    window.addEventListener('message', onMsg);
    try {window.parent.postMessage({ type: '__edit_mode_available' }, '*');} catch {}
    return () => window.removeEventListener('message', onMsg);
  }, []);

  function updateTweak(key, value) {
    setTweaks((t) => {
      const next = { ...t, [key]: value };
      try {window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [key]: value } }, '*');} catch {}
      return next;
    });
  }

  // --- Scroll scene breakdown (photo-strip variant) ---
  // 0.00-0.55 : four scanned photos pan in from the right (PhotoStrip)
  // 0.55-0.62 : date parallaxes UP, photo strip drifts away
  // 0.62-1.00 : envelope reveal → RSVP button
  const p = heroProgress;
  const rotation = 0; // legacy — Library3D no longer in hero
  const envProgress = clamp((p - 0.62) / 0.38);

  // Info cards timing windows — each appears in a slice of the rotation arc
  const infoSlots = [
  {
    at: [0.14, 0.26],
    position: { top: '30%', left: '6%' },
    kicker: 'The Ceremony',
    title: "Scots' Church",
    body: '77 Russell Street, Melbourne VIC 3000 — we will exchange our vows beneath the bluestone spire, a short walk from the State Library.'
  },
  {
    at: [0.30, 0.42],
    position: { top: '52%', right: '6%' },
    kicker: 'The Reception',
    title: 'Inside the dome',
    body: 'Dinner, dancing and long toasts beneath the La Trobe Reading Room — a circular cathedral of books and light.'
  },
  {
    at: [0.46, 0.58],
    position: { top: '28%', right: '6%' },
    kicker: 'The Day',
    title: '29 August 2026',
    body: 'A Saturday evening in late winter. The ceremony begins at four. Dress code: black tie.'
  },
  {
    at: [0.62, 0.72],
    position: { top: '58%', left: '6%' },
    kicker: 'Getting there',
    title: 'Russell Street, Melbourne',
    body: 'Trams pass the front door. Valet is available on La Trobe Street for the evening.'
  }];


  return (
    <>
      <window.Countdown targetDate={tweaks.weddingDate} />
      <nav className="nav">
        <button className="nav-brand" onClick={goHome} aria-label="Home">
          <img
            className="nav-brand-logo"
            src="assets/Logos/A%26N-logo-small.png"
            alt={`${tweaks.brideName} & ${tweaks.groomName}`}
          />
        </button>
        <div className="nav-links">
          <button onClick={() => goTo('details')}>Details</button>
          <button onClick={() => goTo('attire')}>Attire</button>
          <button onClick={() => goTo('hotels')}>Hotels</button>
        </div>
        <button className="nav-cta" onClick={(e) => { goHome(); openRsvp(e); }}>RSVP</button>
      </nav>

      {/* Hero with scroll scene */}
      <section className="hero-scroll" ref={heroRef}>
        <div className={`hero-pin ${p >= 1 ? 'is-done' : ''}`} style={{ opacity: p > 1 ? 0 : 1 }}>
          {/* masthead fades out as we scroll past */}
          <div className="hero-masthead" style={{
            opacity: 1 - clamp(p / 0.14) * 0.9,
            transform: `translateY(${clamp(p / 0.2) * -60}px)`
          }}>
            <h1 className="hero-names">
              {tweaks.brideName} <span className="amp">&amp;</span> {tweaks.groomName}
            </h1>
          </div>

          {/* Welcome message — "Hello Friends & Family" + an invitation
              paragraph. The outer ANCHOR pins itself to the gap between the
              names (above) and the date (below) and flex-centres the
              welcome block in that gap, so the body of copy always sits at
              the exact midpoint. The inner block handles parallax + fade. */}
          <div className="hero-welcome-anchor">
            <div className="hero-welcome" style={{
              transform: `translateY(${clamp(p / 0.55) * -320}px)`,
              opacity: 1 - clamp((p - 0.42) / 0.13)
            }}>
              <h2 className="hero-welcome-heading">Hello Friends &amp; Family,</h2>
              <p className="hero-welcome-body">
                We are so excited to invite you to the wedding of Audrey and Nicholas.
                It will be a joy to celebrate this day with the people who have loved,
                supported, and shaped us throughout our journey together. Every one of
                you holds a special place in our hearts, and we truly couldn't imagine
                our day without you.
              </p>
            </div>
          </div>

          {/* Date — sits in the lower third over the photo strip area, and
              parallaxes UP only AFTER all four photos have been shown. */}
          <div className="hero-date-parallax" style={{
            transform: `translateY(${clamp((p - 0.55) / 0.07) * -240}px)`,
            opacity: 1 - clamp((p - 0.58) / 0.04)
          }}>
            <span className="hero-date">29 August 2026</span>
          </div>

          <div className="hero-building" style={{
            // strip pans + drifts; opacity fades as the envelope grows in
            opacity: 1 - envProgress * 0.9
          }}>
            <window.PhotoStrip progress={clamp(p / 0.62)} />
          </div>

          {/* Envelope sits on top of building */}
          <window.Envelope
            progress={envProgress}
            onOpen={openRsvp} />
          

          {/* (Info cards removed — the photo strip carries the visual narrative
              of the hero and the envelope/RSVP follows directly after the
              date parallaxes up.) */}

          {/* caption + scroll cue */}
          <div className="hero-caption" style={{ opacity: 1 - clamp(p / 0.1) }}>
            Scroll to begin
            <span className="scroll-arrow" />
          </div>

        </div>
      </section>

      {/* Footer */}
      <footer className="site-footer">
        <img
          className="site-footer-logo"
          src="assets/Logos/A%26N-logo-med-cream.png"
          alt={`${tweaks.brideName} & ${tweaks.groomName}`}
        />
        <div className="rule" />
        <div className="line">{tweaks.weddingDate}</div>
      </footer>

      {/* RSVP modal — reveals from the envelope seal with a wax-unfurl clip-path */}
      {rsvpOpen &&
      <div
        className="rsvp-overlay"
        style={rsvpOrigin ? { '--ox': rsvpOrigin.x + 'px', '--oy': rsvpOrigin.y + 'px' } : {}}
        onClick={(e) => {if (e.target === e.currentTarget) setRsvpOpen(false);}}>
        
          <window.RSVPFlow
          sheetEndpoint={tweaks.sheetEndpoint}
          updateToken={rsvpUpdateToken}
          onFinished={(where) => {
            setRsvpOpen(false);
            setRsvpUpdateToken(null);
            if (where === 'details') setDetailsOpen(true);
            else if (where === 'attire') setAttireOpen(true);
          }} />
        
        </div>
      }

      {/* Details */}
      <window.DetailsBoard
        active={detailsOpen}
        onBack={() => setDetailsOpen(false)}
        onOpenAttire={() => { setDetailsOpen(false); setAttireOpen(true); }}
        onOpenHotels={() => { setDetailsOpen(false); setHotelsOpen(true); }}
      />

      {/* Attire */}
      <window.AttireBoard active={attireOpen} onBack={() => setAttireOpen(false)} />

      {/* Hotels */}
      <window.HotelsBoard active={hotelsOpen} onBack={() => setHotelsOpen(false)} />

      {/* Tweaks */}
      {tweakMode &&
      <div className="tweaks-panel open">
          <h5 style={{ fontFamily: "\"New York\"" }}>Tweaks</h5>
          {Object.keys(DEFAULT_TWEAKS).map((k) =>
        <div className="tweak-row" key={k}>
              <label>{k}</label>
              <input
            type={typeof DEFAULT_TWEAKS[k] === 'number' ? 'number' : 'text'}
            value={tweaks[k]}
            onChange={(e) => updateTweak(k, typeof DEFAULT_TWEAKS[k] === 'number' ? Number(e.target.value) : e.target.value)} />
          
            </div>
        )}
          <div className="tweak-row">
            <button onClick={() => openRsvp(null)}>Open RSVP</button>
            <button onClick={() => setAttireOpen(true)}>Open Attire</button>
          </div>
        </div>
      }
    </>);

}

function scrollTo(sel) {
  const el = document.querySelector(sel);
  if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 20, behavior: 'smooth' });
}

function clamp(x, lo = 0, hi = 1) {return Math.max(lo, Math.min(hi, x));}
function easeInOut(x) {return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;}

window.App = App;