/* === RSVP, FAQ, Footer, Nav, App ===
 * Production version: no Tweaks panel (palette / typography baked into CSS).
 * RSVP submits to /api/rsvp.
 */

const RSVP_API_URL = '/api/rsvp';

function RSVP() {
  const [form, setForm] = React.useState({
    namn: '',
    kommer: '',
    antal: '1',
    plus_one_namn: '',
    kost: '',
    halsning: '',
  });
  const [errors, setErrors] = React.useState({});
  const [submitted, setSubmitted] = React.useState(false);
  const [submitting, setSubmitting] = React.useState(false);
  const [serverError, setServerError] = React.useState(null);

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const validate = () => {
    const e = {};
    if (!form.namn.trim()) e.namn = 'Vi behöver ditt namn.';
    if (!form.kommer) e.kommer = 'Snälla, säg ja eller nej.';
    if (form.kommer === 'ja' && (!form.antal || +form.antal < 1)) e.antal = 'Antal personer?';
    setErrors(e);
    return Object.keys(e).length === 0;
  };

  const onSubmit = async (ev) => {
    ev.preventDefault();
    if (submitting) return;
    if (!validate()) return;
    setServerError(null);
    setSubmitting(true);
    try {
      const r = await fetch(RSVP_API_URL, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({
          name: form.namn,
          attending: form.kommer === 'ja',
          party_size: form.kommer === 'ja' ? +form.antal : 0,
          plus_one_name: form.plus_one_namn || null,
          dietary: form.kost || null,
          message: form.halsning || null,
        }),
      });
      if (!r.ok) throw new Error(`Server svarade ${r.status}`);
      setSubmitted(true);
    } catch (err) {
      setServerError('Hmm, något gick fel. Försök igen om en stund eller skriv till oss.');
    } finally {
      setSubmitting(false);
    }
  };

  if (submitted) {
    return (
      <section id="osa" data-screen-label="07 OSA">
        <div className="container">
          <SectionHead num="VII" kicker="Tack!" title="OSA" italicTitle="mottaget" />
          <div className="rsvp">
            <div className="rsvp-confirm">
              <span className="stamp">{form.kommer === 'ja' ? 'Bekräftat · Vi ses!' : 'Mottaget · Vi saknar er'}</span>
              <h3>Tack, {form.namn.split(' ')[0]}.</h3>
              {form.kommer === 'ja' ? (
                <p>Vi har antecknat {form.antal} {+form.antal === 1 ? 'plats' : 'platser'} åt dig{form.plus_one_namn ? ` och ${form.plus_one_namn}` : ''}. Vi hör av oss med fler detaljer när det närmar sig.</p>
              ) : (
                <p>Vi förstår, men vi kommer att sakna dig. Tack för att du tog dig tid att svara!</p>
              )}
              <button className="btn-submit" style={{ marginTop: 28 }} onClick={() => { setSubmitted(false); setForm({ namn: '', kommer: '', antal: '1', plus_one_namn: '', kost: '', halsning: '' }); }}>
                Skicka ett till svar
              </button>
            </div>
          </div>
        </div>
      </section>
    );
  }

  const deadline = (window.CONTENT && window.CONTENT.rsvpDeadline) || '15 juni';

  return (
    <section id="osa" data-screen-label="07 OSA">
      <div className="container">
        <SectionHead num="VII" kicker={`Anmäl er senast ${deadline}`} title="O." italicTitle="S.A." sub="Vänligen meddela om ni kommer eller inte — så vet vi hur många stolar att trolla fram." />
        <form className="rsvp" onSubmit={onSubmit} noValidate>
          <span className="telegram-banner">★ Telegram · Réponse s'il vous plaît ★</span>
          <div className="rsvp-inner">
            <div className={`field ${errors.namn ? 'error' : ''}`}>
              <label htmlFor="namn">Namn</label>
              <input id="namn" type="text" value={form.namn} onChange={e => set('namn', e.target.value)} placeholder="Förnamn och efternamn" autoComplete="name" />
              <div className="field-err">{errors.namn}</div>
            </div>

            <div className={`field ${errors.kommer ? 'error' : ''}`}>
              <label>Kommer du?</label>
              <div className="radio-row">
                <div className={`radio-pill ${form.kommer === 'ja' ? 'selected sage' : ''}`} onClick={() => set('kommer', 'ja')}>Ja, gärna</div>
                <div className={`radio-pill ${form.kommer === 'nej' ? 'selected terra' : ''}`} onClick={() => set('kommer', 'nej')}>Tyvärr inte</div>
              </div>
              <div className="field-err">{errors.kommer}</div>
            </div>

            {form.kommer === 'ja' && (
              <>
                <div className={`field ${errors.antal ? 'error' : ''}`}>
                  <label htmlFor="antal">Antal personer (inkl. ev. +1)</label>
                  <input id="antal" type="number" min="1" max="4" value={form.antal} onChange={e => set('antal', e.target.value)} />
                  <div className="field-err">{errors.antal}</div>
                </div>

                {+form.antal > 1 && (
                  <div className="field">
                    <label htmlFor="plus_one_namn">Namn på sällskap</label>
                    <input id="plus_one_namn" type="text" value={form.plus_one_namn} onChange={e => set('plus_one_namn', e.target.value)} placeholder="För placeringskortet" />
                  </div>
                )}

                <div className="field">
                  <label htmlFor="kost">Specialkost & allergier</label>
                  <textarea id="kost" value={form.kost} onChange={e => set('kost', e.target.value)} placeholder="Vegetariskt, glutenfritt, nötallergi, osv. — eller låt stå tomt." />
                </div>

                <div className="field">
                  <label htmlFor="halsning">En liten hälsning till brudparet (valfritt)</label>
                  <textarea id="halsning" value={form.halsning} onChange={e => set('halsning', e.target.value)} placeholder="Förhoppningar, varningar eller låtönskningar." />
                </div>
              </>
            )}

            {serverError && (
              <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.1em', color: 'var(--oxblood-deep)', textAlign: 'center', marginBottom: 12 }}>
                {serverError}
              </div>
            )}

            <button type="submit" className="btn-submit" disabled={submitting}>
              {submitting ? 'Skickar…' : 'Skicka svar'}
            </button>
          </div>
        </form>
      </div>
    </section>
  );
}

// --- FAQ ---
function FAQ() {
  const [open, setOpen] = React.useState(0);
  const [, setT] = React.useState(0);
  React.useEffect(() => {
    const h = () => setT(x => x + 1);
    window.addEventListener('content:update', h);
    return () => window.removeEventListener('content:update', h);
  }, []);
  const FAQS = (window.CONTENT && window.CONTENT.faqs) || (window.CONTENT_DEFAULTS && window.CONTENT_DEFAULTS.faqs) || [];
  return (
    <section id="fragor" data-screen-label="08 Frågor">
      <div className="container">
        <SectionHead num="VIII" kicker="Frågor & svar" title="Vanliga" italicTitle="frågor" />
        <div className="faq">
          {FAQS.map((f, i) => (
            <div className={`faq-item ${open === i ? 'open' : ''}`} key={i}>
              <button className="faq-q" onClick={() => setOpen(open === i ? -1 : i)} aria-expanded={open === i}>
                <span className="q-num">№ {String(i + 1).padStart(2, '0')}</span>
                <span>{f.q}</span>
                <span className="q-icon">{open === i ? '–' : '+'}</span>
              </button>
              <div className="faq-a" style={{ maxHeight: open === i ? 600 : 0 }}>
                <div className="faq-a-inner">{f.a}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// --- Footer ---
function Footer() {
  const [, setT] = React.useState(0);
  React.useEffect(() => {
    const h = () => setT(x => x + 1);
    window.addEventListener('content:update', h);
    return () => window.removeEventListener('content:update', h);
  }, []);
  const h = (window.CONTENT && window.CONTENT.hero) || {};
  return (
    <footer className="footer">
      <div className="container">
        <Crest />
        <p style={{ fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 18, margin: '8px 0' }}>
          {h.footerItalic || 'Med kärlek från Österlen'}
        </p>
        <div className="small">{h.footerLine || 'Kajsa & Axel · 15 augusti 2026 · Stenladan, Kivik'}</div>
        {h.contact && <div className="small" style={{ marginTop: 6 }}>Frågor? {h.contact}</div>}
      </div>
    </footer>
  );
}

// --- Nav ---
function Nav({ active }) {
  const [open, setOpen] = React.useState(false);
  const [, setT] = React.useState(0);
  React.useEffect(() => {
    const h = () => setT(x => x + 1);
    window.addEventListener('content:update', h);
    return () => window.removeEventListener('content:update', h);
  }, []);
  const scrollTo = (id) => {
    const el = document.getElementById(id);
    if (!el) return;
    const top = el.getBoundingClientRect().top + window.scrollY - 70;
    window.scrollTo({ top, behavior: 'smooth' });
    setOpen(false);
  };
  React.useEffect(() => {
    document.body.style.overflow = open ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [open]);
  const ROMAN = ['I','II','III','IV','V','VI','VII','VIII'];
  const stamp = (window.CONTENT && window.CONTENT.date && window.CONTENT.date.stamp) || '15 · VIII · MMXXVI';
  const a = (window.CONTENT && window.CONTENT.hero && window.CONTENT.hero.coupleA) || 'Kajsa';
  const b = (window.CONTENT && window.CONTENT.hero && window.CONTENT.hero.coupleB) || 'Axel';
  return (
    <nav className="nav">
      <div className="nav-inner">
        <div className="nav-mark">{a} <span className="amp">&amp;</span> {b}</div>
        <div className="nav-center">
          {SECTIONS.map((s, i) => (
            <button key={s.id} className={`nav-link ${active === s.id ? 'active' : ''}`} onClick={() => scrollTo(s.id)}>
              <span className="num">{ROMAN[i]}</span>{s.label}
            </button>
          ))}
        </div>
        <div className="nav-right">
          <span className="nav-date">{stamp}</span>
        </div>
        <button
          className={`nav-burger ${open ? 'open' : ''}`}
          aria-label="Meny"
          aria-expanded={open}
          onClick={() => setOpen(o => !o)}
        >
          <span></span><span></span><span></span>
        </button>
      </div>
      <div className={`nav-drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
        <div className="nav-drawer-inner">
          {SECTIONS.map((s, i) => (
            <button key={s.id} className={`nav-drawer-link ${active === s.id ? 'active' : ''}`} onClick={() => scrollTo(s.id)}>
              <span className="roman">Del {ROMAN[i]}</span>
              <span className="lbl">{s.label}</span>
            </button>
          ))}
          <div className="nav-drawer-foot">{stamp} · Österlen</div>
        </div>
      </div>
    </nav>
  );
}

// --- App ---
function App() {
  const [active, setActive] = React.useState('hem');
  const [, setT] = React.useState(0);
  // First-time visitors have no cache, so window.CONTENT.siteMode is whatever
  // DEFAULTS says (currently 'full') until /api/content responds. Painting
  // before then would briefly show the wrong mode. Hold off until either
  // the cache was a real hit or the server has answered.
  const [hydrated, setHydrated] = React.useState(() => !!window.CONTENT_HYDRATED);

  // Re-render on content:update so Hero/Footer/Nav etc. pick up server hydration.
  React.useEffect(() => {
    const h = () => setT(x => x + 1);
    window.addEventListener('content:update', h);
    return () => window.removeEventListener('content:update', h);
  }, []);

  React.useEffect(() => {
    if (hydrated) return;
    const onUpdate = () => { if (window.CONTENT_HYDRATED) setHydrated(true); };
    window.addEventListener('content:update', onUpdate);
    // Fallback: even if the API is unreachable, give up after 1.5s and
    // render whatever we have (defaults) rather than a permanent blank.
    const t = setTimeout(() => setHydrated(true), 1500);
    return () => { window.removeEventListener('content:update', onUpdate); clearTimeout(t); };
  }, [hydrated]);

  const c = window.CONTENT || window.CONTENT_DEFAULTS || {};
  const mode = c.siteMode || 'full';

  // Toggle a body class so the edge stripes / body padding can stand down in
  // mini modes. Index.html renders the stripes outside the React root.
  React.useEffect(() => {
    document.body.classList.toggle('mode-mini', mode !== 'full');
    return () => { document.body.classList.remove('mode-mini'); };
  }, [mode]);

  // Scrollspy — only meaningful in full mode, but always register the effect
  // so hook order stays consistent across renders.
  React.useEffect(() => {
    if (mode !== 'full') return;
    const onScroll = () => {
      const y = window.scrollY + 120;
      let cur = 'hem';
      for (const s of SECTIONS) {
        const el = document.getElementById(s.id);
        if (el && el.offsetTop <= y) cur = s.id;
      }
      setActive(cur);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, [mode]);

  if (!hydrated) return null;
  if (mode === 'construction') return <UnderConstruction />;
  if (mode === 'savethedate') return <SaveTheDate />;

  return (
    <>
      <Nav active={active} />
      <Hero />
      <Program />
      <Plats />
      <Boende />
      <Kladkod />
      <Presenter />
      <RSVP />
      <FAQ />
      <Footer />
    </>
  );
}

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