// app.jsx — root app with screen routing + tweaks

const { useState: useState_A, useEffect: useEffect_A, useRef: useRef_A } = React;

function PasswordGate({ onUnlock }) {
  const [digits, setDigits] = useState_A(['', '', '', '']);
  const [shake, setShake] = useState_A(false);
  const [unlocking, setUnlocking] = useState_A(false);
  const refs = [useRef_A(), useRef_A(), useRef_A(), useRef_A()];

  const handleKey = (i, val) => {
    if (!/^\d?$/.test(val)) return;
    const next = [...digits];
    next[i] = val.slice(-1);
    setDigits(next);
    if (val && i < 3) refs[i + 1].current.focus();
    if (next.every(d => d !== '') && (val || i === 3)) {
      const code = next.join('');
      if (code === '4444') {
        setUnlocking(true);
        sessionStorage.setItem('rwl-auth', 'ok');
        setTimeout(onUnlock, 600);
      } else {
        setShake(true);
        setTimeout(() => { setShake(false); setDigits(['', '', '', '']); refs[0].current.focus(); }, 600);
      }
    }
  };

  const handleKeyDown = (i, e) => {
    if (e.key === 'Backspace' && !digits[i] && i > 0) refs[i - 1].current.focus();
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'var(--bg)',
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
      gap: 0, zIndex: 1000,
      opacity: unlocking ? 0 : 1, transition: 'opacity 0.5s ease',
    }}>
      <div style={{ textAlign: 'center', marginBottom: 48 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 'clamp(52px, 10vw, 96px)', fontWeight: 800, letterSpacing: '-0.03em', lineHeight: 1, color: 'var(--ink)' }}>
          r we lost<span style={{ color: 'var(--accent)' }}>?</span>
        </div>
        <p style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--ink-soft)', marginTop: 12, letterSpacing: '0.08em' }}>BETA PREVIEW · ENTER CODE</p>
      </div>

      <div style={{
        display: 'flex', gap: 12,
        animation: shake ? 'rwl-shake 0.5s ease' : 'none',
      }}>
        {digits.map((d, i) => (
          <input
            key={i}
            ref={refs[i]}
            type="password"
            inputMode="numeric"
            maxLength={1}
            value={d}
            autoFocus={i === 0}
            onChange={e => handleKey(i, e.target.value)}
            onKeyDown={e => handleKeyDown(i, e)}
            style={{
              width: 64, height: 72,
              textAlign: 'center',
              fontSize: 28, fontWeight: 700,
              fontFamily: 'var(--font-display)',
              background: 'var(--bg)',
              border: `2.5px solid ${d ? 'var(--accent)' : 'var(--ink-line)'}`,
              borderRadius: 16,
              outline: 'none',
              color: 'var(--ink)',
              caretColor: 'transparent',
              transition: 'border-color 0.15s',
            }}
          />
        ))}
      </div>

      <p style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--ink-soft)', marginTop: 32, letterSpacing: '0.05em' }}>
        {shake ? 'wrong code. try again.' : 'four digits ✦'}
      </p>

      <style>{`
        @keyframes rwl-shake {
          0%, 100% { transform: translateX(0); }
          20% { transform: translateX(-8px); }
          40% { transform: translateX(8px); }
          60% { transform: translateX(-6px); }
          80% { transform: translateX(6px); }
        }
      `}</style>
    </div>
  );
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#FF6FA0",
  "showTicker": true
}/*EDITMODE-END*/;

const ACCENT_OPTIONS = ['#F2686C', '#42B5A0', '#FF6FA0', '#E8B72C'];

function App() {
  const [authed, setAuthed] = useState_A(() => sessionStorage.getItem('rwl-auth') === 'ok');
  const [screen, setScreen] = useState_A('landing'); // landing | input | brewing | itinerary | map
  const [showAbout, setShowAbout] = useState_A(false);
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // trip state
  const [places, setPlaces] = useState_A([]);
  const [trip, setTrip] = useState_A({
    where: '',
    stay: '',
    start: '',
    end: '',
    events: [],
  });
  const [itinerary, setItinerary] = useState_A(null);

  // Load shared trip from URL hash (#t=...) after auth
  const didLoadShared = useRef_A(false);
  useEffect_A(() => {
    if (!authed || didLoadShared.current) return;
    didLoadShared.current = true;
    const hash = window.location.hash;
    if (!hash.startsWith('#t=')) return;
    try {
      const { trip: sharedTrip, places: sharedPlaces, days } = window.decodeTrip(hash.slice(3));
      setTrip(sharedTrip);
      setPlaces(sharedPlaces);
      const geo = sharedPlaces.filter(pl => pl.lat && pl.lng);
      // the link carries the sender's day layout — rebuild exactly that, not a fresh random deal
      const built = geo.length > 0
        ? (days ? window.buildItineraryFromDays(geo, sharedTrip, days) : window.buildItinerary(geo, sharedTrip))
        : null;
      setItinerary(built && built.length > 0 ? built : null);
      setScreen('itinerary');
      window.history.replaceState(null, '', window.location.pathname);
    } catch (e) { console.warn('Bad share link:', e); }
  }, [authed]);

  // Auto-save draft while editing or refining the plan (debounced 800ms).
  // Saves which screen she's on, so resuming reopens the itinerary if that's where she left off.
  useEffect_A(() => {
    if (screen !== 'input' && screen !== 'itinerary' && screen !== 'map') return;
    if (!trip.where && places.length === 0) return;
    const onPlan = (screen === 'itinerary' || screen === 'map') && itinerary && itinerary.length > 0;
    const timer = setTimeout(() => window.saveDraft(trip, places, {
      itinerary: onPlan ? itinerary : null,
      screen: onPlan ? 'itinerary' : 'input',
    }), 800);
    return () => clearTimeout(timer);
  }, [trip, places, screen, itinerary]);

  const handleResumeDraft = (draft) => {
    setTrip(draft.trip);
    setPlaces(draft.places);
    if (draft.screen === 'itinerary' && draft.itinerary && draft.itinerary.length > 0) {
      setItinerary(draft.itinerary);
      setScreen('itinerary');
    } else {
      setItinerary(null);
      setScreen('input');
    }
  };

  // apply tweaks via CSS vars
  useEffect_A(() => {
    document.documentElement.style.setProperty('--accent', t.accent || '#F2686C');
  }, [t.accent]);

  // page indicator
  const steps = [
    { key: 'landing', label: '00 / start' },
    { key: 'input', label: '01 / saves' },
    { key: 'itinerary', label: '02 / plan' },
    { key: 'map', label: '03 / map' },
  ];
  const stepIdx = steps.findIndex(s => s.key === screen);

  const tickerItems = ['paste your saves', 'lock your anchors', 'route the chaos', 'go outside', 'you saved 47 cafés', 'we know'];

  if (!authed) return <PasswordGate onUnlock={() => setAuthed(true)} />;

  return (
    <div className="app">
      {/* TOP NAV */}
      <nav className="nav">
        <button className="nav-logo" onClick={() => setScreen('landing')}>
          r we lost<span className="qmark">?</span>
        </button>

        <div className="nav-steps">
          {steps.slice(1).map((s, i) => {
            const idx = i + 1;
            const isActive = idx === stepIdx;
            const isDone = idx < stepIdx;
            return (
              <React.Fragment key={s.key}>
                <button
                  className={`nav-step ${isActive ? 'active' : ''} ${isDone ? 'done' : ''}`}
                  onClick={() => {
                    if (idx <= stepIdx) setScreen(s.key);
                  }}
                  disabled={idx > stepIdx}
                  style={{ opacity: idx > stepIdx ? 0.4 : 1, cursor: idx <= stepIdx ? 'pointer' : 'not-allowed' }}
                >{s.label}</button>
                {i < steps.length - 2 && <span style={{ color: 'var(--ink-soft)' }}>·</span>}
              </React.Fragment>
            );
          })}
        </div>

        <div className="nav-right">
          <span><span className="dot"></span> live</span>
          <button onClick={() => setShowAbout(true)} style={{ cursor: 'pointer', background: 'none', border: 0, padding: 0, font: 'inherit', color: 'inherit', letterSpacing: 'inherit', textTransform: 'inherit' }}>about</button>
        </div>
      </nav>

      {/* ABOUT overlay */}
      {showAbout && (
        <div onClick={() => setShowAbout(false)} style={{ position: 'fixed', inset: 0, background: 'rgba(23,18,17,0.35)', zIndex: 900, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
          <div onClick={e => e.stopPropagation()} style={{ background: 'var(--bg)', border: '1.5px solid var(--ink-line)', borderRadius: 18, boxShadow: '6px 6px 0 var(--ink-line)', maxWidth: 440, padding: '28px 30px', position: 'relative' }}>
            <button onClick={() => setShowAbout(false)} style={{ position: 'absolute', top: 12, right: 14, background: 'none', border: 'none', fontSize: 18, cursor: 'pointer', color: 'var(--ink-soft)', lineHeight: 1 }}>×</button>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 30, letterSpacing: '-0.03em' }}>
              r we lost<span style={{ color: 'var(--accent)' }}>?</span>
            </div>
            <p style={{ fontSize: 14, lineHeight: 1.55, marginTop: 12 }}>
              the trip planner for people who hoard saved places. paste your google maps links,
              lock the non-negotiables, and get a day-by-day route that respects opening hours,
              meal times, and your feet.
            </p>
            <p style={{ fontSize: 14, lineHeight: 1.55, marginTop: 8, color: 'var(--ink-soft)' }}>
              days are clustered by neighborhood, walks are real distances, and dinner is never
              a place that closed at 6.
            </p>
            <p className="mono" style={{ fontSize: 11, marginTop: 16, color: 'var(--ink-soft)', letterSpacing: '0.06em' }}>
              {window.RWL_VERSION} · made with chaos by dip ✦
            </p>
          </div>
        </div>
      )}

      {/* TICKER on landing only */}
      {screen === 'landing' && t.showTicker && (
        <Ticker items={tickerItems} />
      )}

      {/* SCREENS */}
      {screen === 'landing' && <LandingScreen onResumeDraft={handleResumeDraft} onStart={() => {
        setPlaces([]);
        setTrip({ where: '', stay: '', start: '', end: '', events: [] });
        setItinerary(null);
        setScreen('input');
      }} onDemo={() => {
        setPlaces(window.SAMPLE_PLACES.map(p => ({ ...p, resolved: true })));
        setTrip({ where: 'lisbon, portugal', stay: '', start: '2024-10-06', end: '2024-10-08', events: [{ name: 'Bairro do Avillez', day: '1', time: '21:00', placeId: 'p9', lat: 38.7104, lng: -9.1419 }] });
        setItinerary(window.ITINERARY);
        setScreen('input');
      }} />}
      {screen === 'input' && <InputScreen onContinue={() => setScreen('brewing')} places={places} setPlaces={setPlaces} trip={trip} setTrip={setTrip} />}
      {screen === 'brewing' && <BrewingScreen
        task={async (onProgress) => {
          try {
            const { places: resolved, locationBias } = await window.resolvePlacesList(places, trip, onProgress);
            const stayPlace = trip.stay && trip.stay.trim()
              ? await window.resolveOnePlace(trip.stay, locationBias)
              : null;
            const tripWithStay = { ...trip, stayPlace };
            setPlaces(resolved);
            setTrip(tripWithStay);
            const geoPlaces = resolved.filter(p => p.lat && p.lng);
            const computed = geoPlaces.length > 0
              ? window.buildItinerary(geoPlaces, tripWithStay)
              : null;
            setItinerary(computed && computed.length > 0 ? computed : null);
          } catch(err) {
            console.error('Resolution failed:', err);
            setItinerary(null);
          }
        }}
        onDone={() => setScreen('itinerary')}
      />}
      {screen === 'itinerary' && <ItineraryScreen
        onMap={() => setScreen('map')}
        onBack={() => setScreen('input')}
        trip={trip}
        places={places}
        itinerary={itinerary}
        onReroute={(newTrip, newItinerary) => { setTrip(newTrip); setItinerary(newItinerary); }}
        onAddPlace={(pl, newItinerary) => {
          setPlaces(prev => [...prev, pl]);
          if (newItinerary) setItinerary(newItinerary);
        }}
        onRemovePlace={(id, newItinerary) => {
          setPlaces(prev => prev.filter(p => p.id !== id));
          if (newItinerary) setItinerary(newItinerary);
        }}
      />}
      {screen === 'map' && <MapScreen onBack={() => setScreen('itinerary')} itinerary={itinerary} />}

      {/* TWEAKS */}
      <TweaksPanel>
        <TweakSection label="Vibe" />
        <TweakColor
          label="Accent"
          value={t.accent}
          options={ACCENT_OPTIONS}
          onChange={(v) => setTweak('accent', v)}
        />
        <TweakToggle
          label="Ticker tape"
          value={t.showTicker}
          onChange={(v) => setTweak('showTicker', v)}
        />
        <TweakSection label="Navigation" />
        <TweakRadio
          label="Jump to"
          value={screen}
          options={['landing', 'input', 'itinerary', 'map']}
          onChange={(v) => {
            if (v === 'input') { setPlaces([]); setTrip({ where: '', stay: '', start: '', end: '', events: [] }); setItinerary(null); }
            setScreen(v);
          }}
        />
        <TweakSection label="" />
        <div style={{ fontSize: 11, color: 'rgba(41,38,27,0.55)', lineHeight: 1.4 }}>
          accent color flows through buttons, the active day, route lines, and key callouts. ticker can feel chaotic — turn it off for a calmer landing.
        </div>
      </TweaksPanel>
    </div>
  );
}

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