// Hotel Marindela — App orchestrator. Manages state, wraps in iOS frame on
// desktop, full-bleed on mobile, exposes Tweaks.

const { useReducer, useState, useEffect, useMemo, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "paletteId": "forest",
  "typeId": "classic",
  "showNudge": true,
  "frame": "auto"
}/*EDITMODE-END*/;

// ── seed cart (under-ordered on purpose to demo the nudge) ────
function initialState() {
  return {
    screen: 'welcome',
    family: window.FAMILY,
    // pre-seed two items so the menu screen has something visual
    cart: { s2: 1, k1: 1 },
    order: ['s2', 'k1'],
    arrival: '19:00',
    nudgeDismissed: false,
  };
}

function reducer(state, action) {
  switch (action.type) {
    case 'go': return { ...state, screen: action.screen };
    case 'add': {
      const cart = { ...state.cart, [action.id]: (state.cart[action.id] || 0) + 1 };
      const order = state.order.includes(action.id) ? state.order : [...state.order, action.id];
      return { ...state, cart, order };
    }
    case 'dec': {
      const cur = state.cart[action.id] || 0;
      if (cur <= 1) {
        const { [action.id]: _, ...rest } = state.cart;
        return { ...state, cart: rest, order: state.order.filter(id => id !== action.id) };
      }
      return { ...state, cart: { ...state.cart, [action.id]: cur - 1 } };
    }
    case 'remove': {
      const { [action.id]: _, ...rest } = state.cart;
      return { ...state, cart: rest, order: state.order.filter(id => id !== action.id) };
    }
    case 'setArrival': return { ...state, arrival: action.value };
    case 'dismissNudge': return { ...state, nudgeDismissed: true };
    case 'confirm': return { ...state, screen: 'confirm' };
    case 'reset': return { ...initialState(), nudgeDismissed: false };
    default: return state;
  }
}

// ── Progress dots on top (subtle stepper) ─────────────────────
function ProgressDots({ screen, palette: p }) {
  const stepOf = { welcome: 0, menu: 1, verify: 2, confirm: 3 };
  const i = stepOf[screen] ?? 0;
  return (
    <div style={{
      position: 'absolute', top: 'calc(env(safe-area-inset-top, 0px) + 60px)',
      left: '50%', transform: 'translateX(-50%)', zIndex: 30, display: 'none',
    }}>
      <div style={{ display: 'flex', gap: 6 }}>
        {[0,1,2,3].map(n => (
          <div key={n} style={{
            width: i === n ? 18 : 6, height: 6, borderRadius: 3,
            background: n <= i ? p.ink : p.line, transition: 'all .3s ease',
          }} />
        ))}
      </div>
    </div>
  );
}

// ── Screen orchestrator with cross-fade transitions ───────────
function ScreenStack({ state, dispatch, palette, type }) {
  const screens = {
    welcome: ScreenWelcome,
    menu: ScreenMenu,
    verify: ScreenVerify,
    confirm: ScreenConfirm,
  };
  // Maintain a stack so transitions can run
  const [current, setCurrent] = useState(state.screen);
  const [outgoing, setOutgoing] = useState(null);
  const stepIdx = { welcome: 0, menu: 1, verify: 2, confirm: 3 };

  useEffect(() => {
    if (state.screen !== current) {
      setOutgoing({ screen: current, dir: (stepIdx[state.screen] > stepIdx[current]) ? 'forward' : 'back' });
      setCurrent(state.screen);
      const id = setTimeout(() => setOutgoing(null), 380);
      return () => clearTimeout(id);
    }
  }, [state.screen]);

  const Current = screens[current];
  const Outgoing = outgoing ? screens[outgoing.screen] : null;

  return (
    <div style={{ position: 'relative', height: '100%', overflow: 'hidden' }}>
      {Outgoing && (
        <div key={`out-${outgoing.screen}`} style={{
          position: 'absolute', inset: 0,
          animation: `screen-out-${outgoing.dir} .38s cubic-bezier(0.4,0,0.2,1) forwards`,
          pointerEvents: 'none',
        }}>
          <Outgoing state={state} dispatch={dispatch} palette={palette} type={type} />
        </div>
      )}
      <div key={`in-${current}`} style={{
        position: 'absolute', inset: 0,
        animation: outgoing
          ? `screen-in-${outgoing.dir} .38s cubic-bezier(0.4,0,0.2,1) forwards`
          : undefined,
      }}>
        <Current state={state} dispatch={dispatch} palette={palette} type={type} />
      </div>
    </div>
  );
}

// ── Theme preset switcher (floating, always visible) ──────────
const THEME_PRESETS = [
  { id: 'editorial', label: 'Editorial', paletteId: 'forest', typeId: 'classic' },
  { id: 'gxLight',   label: 'GX · Light', paletteId: 'gxLight', typeId: 'gx' },
  { id: 'gxDark',    label: 'GX · Dark',  paletteId: 'gx',      typeId: 'gx' },
];
function ThemePresets({ paletteId, typeId, onPick }) {
  const activeId = THEME_PRESETS.find(p => p.paletteId === paletteId && p.typeId === typeId)?.id;
  return (
    <div style={{
      position: 'fixed', top: 12, left: '50%', transform: 'translateX(-50%)',
      zIndex: 1000, display: 'flex', gap: 2, padding: 3,
      background: 'rgba(255,255,255,0.86)',
      border: '1px solid rgba(0,0,0,0.10)',
      borderRadius: 999,
      backdropFilter: 'blur(10px)',
      WebkitBackdropFilter: 'blur(10px)',
      boxShadow: '0 6px 18px rgba(0,0,0,0.08)',
      fontFamily: '"Inter", -apple-system, system-ui, sans-serif',
      fontSize: 11.5, lineHeight: 1,
    }}>
      {THEME_PRESETS.map(p => {
        const active = p.id === activeId;
        return (
          <button key={p.id} onClick={() => onPick(p)} style={{
            padding: '7px 12px', border: 0, borderRadius: 999, cursor: 'pointer',
            background: active ? '#1A1A26' : 'transparent',
            color: active ? '#FFF' : '#5A5A6A',
            fontFamily: 'inherit', fontSize: 'inherit', fontWeight: active ? 500 : 400,
            letterSpacing: '0.01em',
            transition: 'background .15s ease, color .15s ease',
          }}>{p.label}</button>
        );
      })}
    </div>
  );
}

// ── Top-level App ─────────────────────────────────────────────
function App() {
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [state, dispatch] = useReducer(reducer, undefined, initialState);
  const palette = window.PALETTES[tw.paletteId] || window.PALETTES.forest;
  const type = window.TYPE_PAIRS[tw.typeId] || window.TYPE_PAIRS.classic;

  // Decide framing — auto picks based on viewport width
  const [vw, setVW] = useState(window.innerWidth);
  useEffect(() => {
    const onR = () => setVW(window.innerWidth);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);
  const framed = tw.frame === 'frame' || (tw.frame === 'auto' && vw >= 720);

  // Inject font CSS variables onto root
  const rootStyle = useMemo(() => ({
    '--font-display': type.display,
    '--font-body': type.body,
    color: palette.ink,
    background: palette.bg,
    fontFamily: type.body,
  }), [type, palette]);

  // Override starter component to use ours
  const Inner = (
    <ScreenStack state={state} dispatch={dispatch} palette={palette} type={type} />
  );

  return (
    <div style={rootStyle} className="app-root">
      {framed ? (
        <FramedView palette={palette} type={type} state={state} dispatch={dispatch}>
          {Inner}
        </FramedView>
      ) : (
        <div style={{
          position: 'fixed', inset: 0, background: palette.bg,
          display: 'flex', flexDirection: 'column',
        }}>{Inner}</div>
      )}

      {framed && (
        <ThemePresets paletteId={tw.paletteId} typeId={tw.typeId}
          onPick={(p) => { setTweak('paletteId', p.paletteId); setTweak('typeId', p.typeId); }} />
      )}

      <TweaksPanel>
        <TweakSection label="Palette" />
        <TweakRadio label="Theme" value={tw.paletteId}
          options={Object.entries(window.PALETTES).map(([id, v]) => ({ value: id, label: v.label.split(' & ')[0] }))}
          onChange={(v) => setTweak('paletteId', v)} />
        <TweakSection label="Typography" />
        <TweakSelect label="Pair" value={tw.typeId}
          options={Object.entries(window.TYPE_PAIRS).map(([id, v]) => ({ value: id, label: v.label }))}
          onChange={(v) => setTweak('typeId', v)} />
        <TweakSection label="Frame" />
        <TweakRadio label="Display" value={tw.frame}
          options={[{ value: 'auto', label: 'Auto' }, { value: 'frame', label: 'Phone' }, { value: 'full', label: 'Bleed' }]}
          onChange={(v) => setTweak('frame', v)} />
        <TweakSection label="Flow" />
        <TweakButton label="Jump to confirm"
          onClick={() => dispatch({ type: 'confirm' })} />
        <TweakButton label="Reset to welcome"
          onClick={() => dispatch({ type: 'reset' })} />
      </TweaksPanel>
    </div>
  );
}

// ── Framed view (desktop) ─────────────────────────────────────
function FramedView({ children, palette, type, state, dispatch }) {
  const screenLabels = {
    welcome: '01 · Welcome',
    menu: '02 · Menu',
    verify: '03 · Arrival',
    confirm: '04 · Confirmed',
  };
  // Phone size adapts to viewport height so the whole device stays visible.
  const [vh, setVH] = useState(window.innerHeight);
  useEffect(() => {
    const onR = () => setVH(window.innerHeight);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);
  const phoneH = Math.max(640, Math.min(800, vh - 40));
  const phoneW = Math.round(phoneH * 0.485);
  return (
    <div style={{
      position: 'fixed', inset: 0, overflow: 'auto',
      background: `radial-gradient(ellipse at top, ${palette.surfaceAlt} 0%, ${palette.bg} 60%)`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '24px',
    }}>
      {/* left context — design label */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 40, flexWrap: 'wrap',
        justifyContent: 'center', maxWidth: 1200,
      }}>
        <aside style={{ maxWidth: 280, color: palette.ink }}>
          <div style={{
            fontFamily: type.display, fontWeight: type.displayWeight,
            fontSize: 14, letterSpacing: '0.22em', textTransform: 'uppercase',
            color: palette.inkSoft, marginBottom: 8,
          }}>Hotel Marindela</div>
          <h1 style={{
            margin: 0, fontFamily: type.display, fontWeight: type.displayWeight,
            fontSize: 44, lineHeight: 1.02, letterSpacing: '-0.015em',
            color: palette.ink,
          }}>
            F&amp;B pre-order, <span style={{ fontStyle: 'italic' }}>before arrival.</span>
          </h1>
          <p style={{
            margin: '20px 0 28px', fontSize: 14.5, lineHeight: 1.6,
            color: palette.inkSoft, fontFamily: type.body,
          }}>
            A concierge-first family flow: welcome, choose dinner, set arrival,
            confirm. Kids' plates are timed to land first.
          </p>
          <div style={{
            display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12.5,
            color: palette.inkSoft, fontFamily: type.body,
          }}>
            {Object.entries(screenLabels).map(([k, label]) => (
              <button key={k} onClick={() => dispatch({ type: 'go', screen: k })}
                style={{
                  display: 'flex', alignItems: 'center', gap: 10,
                  background: 'transparent', border: 0, padding: '6px 0',
                  color: state.screen === k ? palette.ink : palette.inkSoft,
                  cursor: 'pointer', fontFamily: 'inherit', fontSize: 12.5,
                  textAlign: 'left',
                }}>
                <span style={{
                  width: 14, height: 1, background: state.screen === k ? palette.ink : palette.line,
                  display: 'inline-block',
                }} />
                {label}
              </button>
            ))}
          </div>
        </aside>

        <div data-screen-label={`Hotel Marindela · ${state.screen}`} style={{
          width: phoneW, height: phoneH, borderRadius: 48, overflow: 'hidden',
          position: 'relative', background: palette.bg,
          boxShadow: '0 40px 80px rgba(0,0,0,0.18), 0 0 0 12px #0E0C0A, 0 0 0 13px #2D2823',
        }}>
          {/* dynamic island */}
          <div style={{
            position: 'absolute', top: 11, left: '50%', transform: 'translateX(-50%)',
            width: 110, height: 32, borderRadius: 20, background: '#000', zIndex: 50,
          }} />
          {/* status bar */}
          <div style={{
            position: 'absolute', top: 0, left: 0, right: 0, zIndex: 40,
            display: 'flex', justifyContent: 'space-between', padding: '18px 28px 0',
            pointerEvents: 'none',
          }}>
            <span style={{
              fontFamily: '-apple-system, system-ui, sans-serif', fontWeight: 600,
              fontSize: 14, color: palette.ink,
            }}>9:41</span>
            <span style={{
              fontFamily: '-apple-system, system-ui, sans-serif', fontWeight: 600,
              fontSize: 12, color: palette.ink, letterSpacing: '0.05em',
            }}>
              <svg width="50" height="14" viewBox="0 0 50 14" style={{ verticalAlign: 'middle' }}>
                <rect x="0" y="9" width="3" height="5" rx="0.5" fill={palette.ink}/>
                <rect x="4" y="6" width="3" height="8" rx="0.5" fill={palette.ink}/>
                <rect x="8" y="3" width="3" height="11" rx="0.5" fill={palette.ink}/>
                <rect x="12" y="0" width="3" height="14" rx="0.5" fill={palette.ink}/>
                <rect x="32" y="2" width="14" height="10" rx="2.5" fill="none" stroke={palette.ink} strokeOpacity="0.5"/>
                <rect x="34" y="4" width="10" height="6" rx="1" fill={palette.ink}/>
              </svg>
            </span>
          </div>
          {/* Pad top for status bar */}
          <div style={{ position: 'absolute', inset: 0, paddingTop: 50 }}>
            <div style={{ height: '100%' }}>{children}</div>
          </div>
          {/* home indicator */}
          <div style={{
            position: 'absolute', bottom: 0, left: 0, right: 0, height: 34, zIndex: 60,
            display: 'flex', justifyContent: 'center', alignItems: 'flex-end',
            paddingBottom: 8, pointerEvents: 'none',
          }}>
            <div style={{
              width: 134, height: 5, borderRadius: 100, background: palette.ink, opacity: 0.3,
            }} />
          </div>
        </div>
      </div>
    </div>
  );
}

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