/* App shell - state, routing, device frame, tweaks */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "device": "iPhone",
  "systemDark": false,
  "startAt": "Home",
  "hero": "Blurred backdrop",
  "express": "Wallet",
  "sim": "none"
}/*EDITMODE-END*/;
const EXAMPLES = [['★ Approval test · free + paid pass', DP.DEMO.apprTest], ['Standard · guest list + media', DP.DEMO.standard], ['Waiting list (sold out)', DP.DEMO.waitSold], ['Waiting list open', DP.DEMO.waitOpen], ['Approval required · free', DP.DEMO.apprFree], ['Approval · paid hold + fee incl.', DP.DEMO.apprPaid], ['Seated · section picker', DP.DEMO.seatSections], ['Seated · row & seat picker', DP.DEMO.seatRows], ['Long title / address / tiers', DP.DEMO.long], ['Price range (0–max)', DP.DEMO.range], ['Organiser questions at checkout', DP.DEMO.standard + 'q'], ['Group table + extra seats', DP.DEMO.group]];

function Phone({ t, onDark }) {
  const [stage, setStage] = useState(t.startAt === 'Home' ? 'app' : 'splash');
  const [tab, setTabRaw] = useState('home');
  const [city, setCity] = useState('Berlin');
  const [saved, setSaved] = useState(new Set(['ev' + (DP.DEMO.standard + 1), 'ev' + (DP.DEMO.festival + 1)]));
  const [bookings, setBookings] = useState(INITIAL_BOOKINGS);
  const [themePref, setThemePref] = useState('system');
  const [currency, setCurrency] = useState('EUR');
  const [notif, setNotif] = useState({ reminders: true, city: true, offers: false });
  const [stack, setStack] = useState([]); // pushed screens: {k:'event',ev} | {k:'ticket',b} | {k:'search'}
  const [closing, setClosing] = useState(false);
  const [success, setSuccess] = useState(null); const [sending, setSending] = useState(null);
  const [cityOpen, setCityOpen] = useState(false); const [notifOpen, setNotifOpen] = useState(false); const [sheet, setSheet] = useState('');
  const [otpTo, setOtpTo] = useState(''); const [toastMsg, setToastMsg] = useState('');
  const [refund, setRefund] = useState(undefined); const [msgEv, setMsgEv] = useState(null);
  useEffect(() => { window.openRefund = (ev) => setRefund(ev || null); }, []);
  const [share, setShare] = useState(null); const [map, setMap] = useState(null); const [media, setMedia] = useState(null); const [artist, setArtist] = useState(null);
  const [waitlisted, setWaitlisted] = useState(new Set(['ev' + (DP.DEMO.waitSold + 1)]));
  useEffect(() => { window.setShareHandler((ev) => setShare(ev)); window.openShare = (ev) => setShare(ev); }, []);
  useEffect(() => { if (t.jump != null && t.jump !== '') { const ev = DP.EVENTS[t.jump]; if (ev) { setStage('app'); setStack([{ k: 'event', ev }]); } } }, [t.jump]);
  const toast = (m) => { setToastMsg(m); setTimeout(() => setToastMsg(''), 2200); };
  const dark = themePref === 'dark' || (themePref === 'system' && t.systemDark);
  const ios = t.device === 'iPhone';
  useEffect(() => { onDark(dark || stage === 'splash' || stage === 'intro' || stage === 'signin' || !!sending || !!success); }, [dark, stage, sending, success]);
  const toggleSave = (id) => setSaved(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const push = (item) => setStack(s => [...s, item]);
  const pop = () => { setClosing(true); setTimeout(() => { setStack(s => s.slice(0, -1)); setClosing(false); }, 330); };
  const setTab = (k) => { if (k === tab) return; setTabRaw(k); };
  const openEvent = (ev) => push({ k: 'event', ev });
  const onPaid = ({ ev, qty, tiers, total, pm, n, section, seats, guests, status }) => { const cats = tiers.filter(x => qty[x.k] && !x.hidden); const tickets = tiers.flatMap(x => Array.from({ length: qty[x.k] || 0 }, () => x.nm)); const tier = cats.length === 1 ? cats[0].nm : cats.map(x => x.nm).join(' + '); const b = { id: 'b' + Date.now(), ev, n, tier, tickets, cats: cats.length, total, pm, section, seats, guests, status, code: 'DP-' + Math.random().toString(36).slice(2, 6).toUpperCase() + '-' + Math.random().toString(36).slice(2, 4).toUpperCase() }; setBookings(bs => [b, ...bs]); if (b.status === 'pending') setSending(b); else setSuccess(b); };
  const bookedIds = useMemo(() => new Set(bookings.filter(b => b.status === 'confirmed').map(b => b.ev.id)), [bookings]);
  const openSheet = (k, v) => { if (k === 'share') setShare(v); else if (k === 'map') setMap(v); else if (k === 'media') setMedia(v); else if (k === 'ticket') { const b = bookings.find(x => x.ev.id === v.id); if (b) push({ k: 'ticket', b }); } };
  const toggleWait = (ev, on) => { setWaitlisted(s => { const n = new Set(s); on ? n.add(ev.id) : n.delete(ev.id); return n; }); setBookings(bs => on ? [{ id: 'w' + ev.id, ev, n: 1, tier: 'General', total: 0, pm: '', code: 'DP-WAIT', status: 'waitlist', pos: 12 }, ...bs] : bs.filter(b => !(b.status === 'waitlist' && b.ev.id === ev.id))); toast(on ? "You're on the waiting list" : 'Left the waiting list'); };
  const ctx = { sim: t.sim, express: t.express === 'Saved card' ? 'card' : 'wallet', hero: t.hero === 'Inset card' ? 'inset' : 'blur', dark, device: ios ? 'ios' : 'android', topInset: ios ? 56 : 8, bottomInset: ios ? 30 : 8, city, setCity, saved, toggleSave, themePref, setThemePref, currency, setCurrency, notif, setNotif, setStage, toast };
  const top = stack[stack.length - 1];
  return (
    <AppCtx.Provider value={ctx}>
      <div className="ph" data-theme={dark ? 'dark' : 'light'}>
        {stage === 'splash' && <Splash onDone={() => setStage('intro')} />}
        {stage === 'intro' && <Onboarding onDone={() => setStage('signin')} />}
        {stage === 'signin' && <SignIn onDone={({ via, to }) => { if (via === 'email' || via === 'phone') { setOtpTo(to); setStage('otp'); } else setStage('loc'); }} />}
        {stage === 'otp' && <OTP to={otpTo} onBack={() => setStage('signin')} onDone={() => setStage('loc')} />}
        {stage === 'loc' && <LocationAsk onDone={() => { setCity('Berlin'); setStage('app'); }} onPick={() => { setStage('app'); setCityOpen(true); }} />}
        {stage === 'app' && <>
          <div key={tab} className="fade-in" style={{ position: 'absolute', inset: 0 }}>
            {tab === 'home' && <Home onOpen={openEvent} onSearch={() => push({ k: 'search' })} onCity={(c) => typeof c === 'string' ? setCity(c) : setCityOpen(true)} onBell={() => setNotifOpen(true)} onArtist={setArtist} />}
            {tab === 'bookings' && <Bookings bookings={bookings} onOpen={(b) => push(b.status === 'confirmed' ? { k: 'ticket', b } : { k: 'event', ev: b.ev })} onExplore={() => setTab('home')} />}
            {tab === 'favorites' && <Favorites onOpen={openEvent} onExplore={() => setTab('home')} />}
            {tab === 'profile' && <Profile onSheet={(k) => k === 'city' ? setCityOpen(true) : setSheet(k)} onSignOut={() => { setStack([]); setStage('signin'); }} />}
          </div>
          <TabBar tab={tab} setTab={setTab} />
          {stack.map((it, i) => { const isTop = i === stack.length - 1, cl = isTop && closing; if (it.k === 'event') return <EventDetail key={i} z={30 + i} ev={it.ev} closing={cl} onBack={pop} onOpen={openEvent} onBook={(ev, q) => push({ k: 'checkout', ev, q })} onPaid={onPaid} booked={bookedIds.has(it.ev.id)} pending={bookings.find(b => b.status === 'pending' && b.ev.id === it.ev.id)} declined={bookings.find(b => b.status === 'declined' && b.ev.id === it.ev.id)} onWithdraw={(b) => { setBookings(bs => bs.filter(x => x.id !== b.id)); toast('Request withdrawn'); }} waiting={waitlisted.has(it.ev.id)} onWaitlist={(on) => toggleWait(it.ev, on)} onSheet={openSheet} />; if (it.k === 'checkout') return <Checkout key={i} z={30 + i} ev={it.ev} initialQty={it.q} closing={cl} onBack={pop} onPaid={onPaid} />; if (it.k === 'ticket') return <TicketPass key={i} z={30 + i} booking={it.b} closing={cl} onBack={pop} />; if (it.k === 'search') return <SearchScreen key={i} z={30 + i} onBack={pop} onOpen={openEvent} />; })}
          {success && <Success booking={success} onTicket={() => { setSuccess(null); setStack([{ k: 'ticket', b: success }]); setTabRaw('bookings'); }} onHome={() => { setSuccess(null); setStack([]); setTabRaw('home'); }} />}
          <RefundSheet open={refund !== undefined} ev={refund} onClose={() => setRefund(undefined)} onMessage={(ev) => { setRefund(undefined); setTimeout(() => setMsgEv(ev), 250); }} onBookings={() => { setRefund(undefined); setStack([]); setTabRaw('bookings'); }} />
          <MessageOrganiser open={!!msgEv} onClose={() => setMsgEv(null)} ev={msgEv || {}} />
          {sending && <RequestSending booking={sending} onDone={() => { setSending(null); setStack(s => s.filter(x => x.k !== 'checkout')); }} />}
          <CityPicker open={cityOpen} onClose={() => setCityOpen(false)} />
          <NotifSheet open={notifOpen} onClose={() => setNotifOpen(false)} onOpen={openEvent} />
          <SettingsSheets sheet={sheet} close={() => setSheet('')} toast={toast} />
          <ShareSheet ev={share} open={!!share} onClose={() => setShare(null)} />
          <MapSheet ev={map} open={!!map} onClose={() => setMap(null)} />
          <ArtistSheet artist={artist} open={!!artist} onClose={() => setArtist(null)} onOpen={openEvent} />
          <MediaViewer data={media} onClose={() => setMedia(null)} />
          {t.sim === 'offline' && <OfflineBanner />}
          <Toast msg={toastMsg} />
        </>}
      </div>
    </AppCtx.Provider>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const ios = t.device === 'iPhone';
  const Frame = ios ? IOSDevice : AndroidDevice;
  const [frameDark, setFrameDark] = useState(true);
  const [key, setKey] = useState(0);
  return <>
    <div style={{ transform: 'scale(var(--s,1))', transformOrigin: 'top center' }}>
      <Frame dark={frameDark} width={ios ? 402 : 412} height={ios ? 874 : 892}><div style={{ height: '100%' }}><Phone key={key + t.device + t.startAt} t={t} onDark={setFrameDark} /></div></Frame>
    </div>
    <TweaksPanel>
      <TweakSection label="Device" />
      <TweakRadio label="Frame" value={t.device} options={['iPhone', 'Android']} onChange={v => setTweak('device', v)} />
      <TweakToggle label="OS dark mode" value={t.systemDark} onChange={v => setTweak('systemDark', v)} />
      <TweakSection label="Event detail" />
      <TweakRadio label="Poster" value={t.hero} options={['Blurred backdrop', 'Inset card']} onChange={v => setTweak('hero', v)} />
      <TweakRadio label="Express pay" value={t.express} options={['Wallet', 'Saved card']} onChange={v => setTweak('express', v)} />
      <TweakSection label="Simulate" />
      <TweakSelect label="Edge state" value={t.sim} options={[{ value: 'none', label: 'Nothing (happy path)' }, { value: 'declined', label: 'Card declined at Pay' }, { value: '3ds', label: '3-D Secure at Pay' }, { value: 'soldout', label: 'Sold out at Pay' }, { value: 'session', label: 'Session expired at Pay' }, { value: 'evfail', label: 'Event fails to load' }, { value: 'offline', label: 'Offline' }, { value: 'locdenied', label: 'Location permission denied' }]} onChange={v => setTweak('sim', v)} />
      <TweakSection label="Prototype" />
      <TweakRadio label="Start at" value={t.startAt} options={['Splash', 'Home']} onChange={v => setTweak('startAt', v)} />
      <TweakSelect label="Jump to example" value={t.jump == null ? '' : String(t.jump)} options={[{ value: '', label: '-' }, ...EXAMPLES.map(([l, i]) => ({ value: String(i), label: l }))]} onChange={v => { setTweak('jump', ''); setTimeout(() => setTweak('jump', v === '' ? '' : parseInt(v, 10)), 0); }} />
      <TweakButton label="Replay from splash" onClick={() => { setTweak('startAt', 'Splash'); setKey(k => k + 1); }} />
    </TweaksPanel>
  </>;
}

const fit = () => { const h = window.innerHeight - 40, s = Math.min(1, h / 900); document.documentElement.style.setProperty('--s', s); document.body.style.alignItems = s < 1 ? 'flex-start' : 'center'; };
fit(); window.addEventListener('resize', fit);
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
