// Ludilove — production app shell. Fills the device, no mockup chrome.

function App() {
  const [screen, setScreen] = React.useState(() => {
    const loggedIn = window.LLAPI && window.LLAPI.isLoggedIn();
    // Si déjà connecté : reprend le dernier écran utile, sinon home (feed communauté).
    if (loggedIn) {
      const stored = localStorage.getItem('ll:screen');
      // On ignore onboarding/login/signup pour un user connecté
      if (stored && !['onboarding', 'login', 'signup'].includes(stored)) return stored;
      return 'home';
    }
    // Pas connecté : TOUJOURS login (on ignore le localStorage).
    return 'login';
  });
  const [currentGame, setCurrentGame] = React.useState(null);
  const [currentSession, setCurrentSession] = React.useState(null);
  const [user, setUser] = React.useState(null);
  const [booting, setBooting] = React.useState(true);
  const [banner, setBanner] = React.useState(null);

  React.useEffect(() => { localStorage.setItem('ll:screen', screen); }, [screen]);

  // Global session listener — when the host launches the game, every other
  // client transitions to the first-player draw. We combine SSE (fast) with a
  // polling fallback (survives Cloudflare tunnel, mobile, etc).
  const screenRef = React.useRef(screen);
  React.useEffect(() => { screenRef.current = screen; }, [screen]);
  React.useEffect(() => {
    if (!currentSession?.id) return;

    // Central handler — called from both SSE and polling.
    // Transitions fire ONLY on status CHANGE so the polling can't yank the
    // user back (fixed: first-player was re-appearing randomly because every
    // poll with status='playing' re-triggered the transition).
    const prevStatusRef = { current: currentSession?.status || null };
    const handleSessionUpdate = (sess) => {
      if (!sess) return;
      setCurrentSession(sess);
      const cur = screenRef.current;
      const prev = prevStatusRef.current;

      if (sess.status === 'swiping' && prev !== 'swiping' && cur === 'lobby') {
        setScreen('swipe');
      }

      if (sess.matched_game_id && sess.status === 'playing' && prev !== 'playing') {
        if (!currentGame || currentGame.id !== sess.matched_game_id) {
          const g = window.GAMES.find(x => x.id === sess.matched_game_id);
          if (g) setCurrentGame(g);
        }
        if (cur !== 'first-player') setScreen('first-player');
      }
      prevStatusRef.current = sess.status;
    };

    const unsub = LLAPI.subscribe(currentSession.id, (evt) => {
      if (evt.type === 'launch' && evt.session) {
        handleSessionUpdate(evt.session);
      } else if (evt.session) {
        handleSessionUpdate(evt.session);
      }
    });

    // Polling fallback — survives dead SSE (Cloudflare tunnel, mobile proxy).
    const poll = setInterval(async () => {
      try {
        const { session: s } = await LLAPI.session(currentSession.id);
        if (s) handleSessionUpdate(s);
      } catch (_) {}
    }, 2500);

    return () => { unsub(); clearInterval(poll); };
  }, [currentSession?.id]);

  React.useEffect(() => {
    (async () => {
      try {
        if (LLAPI.isLoggedIn()) {
          try { const me = await LLAPI.me(); setUser(me.user); }
          catch (_) { LLAPI.logout(); }
        }
        const { games } = await LLAPI.games();
        if (games && games.length) {
          window.GAMES.length = 0;
          for (const g of games) window.GAMES.push(g);
          setCurrentGame(games[0]);
        }

        // Deep-link: ?join=CODE → ensure logged in, join the session, hop to lobby
        const url = new URL(window.location.href);
        const joinCode = url.searchParams.get('join');
        if (joinCode) {
          // Strip the param so a refresh doesn't re-join
          url.searchParams.delete('join');
          window.history.replaceState({}, '', url.pathname + (url.search || '') + url.hash);
          if (!LLAPI.isLoggedIn()) {
            localStorage.setItem('ll:pendingJoin', joinCode);
            flash('Connecte-toi pour rejoindre la session');
            setScreen('login');
          } else {
            try {
              const { session } = await LLAPI.joinSession(joinCode);
              setCurrentSession(session);
              setScreen('lobby');
            } catch (err) {
              flash('Code de session invalide ou expiré');
            }
          }
        }
      } catch (err) {
        console.warn('boot:', err);
      } finally {
        setBooting(false);
      }
    })();
  }, []);

  function goto(id) { setScreen(id); }
  function openGame(g) { setCurrentGame(g); setScreen('product'); }
  function openGameShop(g) { setCurrentGame(g); setScreen('product-shop'); }
  function onNav(id) {
    if (id === 'home') setScreen('home');
    else if (id === 'session')  setScreen('new-session');
    else if (id === 'discover') setScreen('discover');
    else if (id === 'add') setScreen('library');
    else if (id === 'profile') setScreen('profile');
  }

  function flash(msg, ms = 2200) {
    setBanner(msg);
    setTimeout(() => setBanner(null), ms);
  }

  async function consumePendingJoin() {
    const code = localStorage.getItem('ll:pendingJoin');
    if (!code) return false;
    localStorage.removeItem('ll:pendingJoin');
    try {
      const { session } = await LLAPI.joinSession(code);
      setCurrentSession(session);
      setScreen('lobby');
      return true;
    } catch (err) {
      flash('Code de session invalide ou expiré');
      return false;
    }
  }

  async function handleAuthDone(u) {
    if (u) setUser(u);
    const joined = await consumePendingJoin();
    if (!joined) goto('home');
  }

  async function handleSessionStart(opts) {
    if (!user) {
      flash('Connecte-toi pour créer une session');
      return goto('login');
    }
    try {
      const { session } = await LLAPI.createSession(opts);
      setCurrentSession(session);
      goto('lobby');
    } catch (err) {
      flash('Erreur : ' + err.message);
    }
  }

  function renderScreen() {
    switch (screen) {
      case 'onboarding':
        return <OnboardingScreen
          onContinue={() => goto('login')}
          onSignup={() => goto('signup')} />;
      case 'signup':
        return <SignupScreen
          onBack={() => goto('onboarding')}
          onDone={handleAuthDone}
          flash={flash} />;
      case 'login':
        return <LoginScreen
          onBack={() => goto('onboarding')}
          onSignup={() => goto('signup')}
          onDone={handleAuthDone}
          flash={flash} />;
      case 'new-session':
        return <NewSessionScreen onNav={onNav} onStart={handleSessionStart}
          onHistory={() => goto('history')} onFeed={() => goto('feed')} user={user} />;
      case 'lobby':
        return <LobbyScreen onBack={() => goto('new-session')} session={currentSession}
          setSession={setCurrentSession} user={user}
          onStart={async () => {
            if (!currentSession) return goto('swipe');
            try { await LLAPI.startSession(currentSession.id); } catch (_) {}
            goto('swipe');
          }} />;
      case 'swipe':
        return <SwipeScreen onNav={onNav} session={currentSession}
          onMatch={(g) => { setCurrentGame(g); goto('match'); }} />;
      case 'match':
        return <MatchScreen game={currentGame}
          onClose={() => goto('swipe')} onPlay={() => goto('product')} />;
      case 'product':
        return <ProductScreen game={currentGame} onBack={() => goto('library')}
          onNav={onNav} onStartGame={async () => {
            // If we're in a multiplayer session AND we're the host, broadcast
            // the launch so every peer's app transitions too. Non-hosts wait
            // — the global listener will move them when the event arrives.
            if (currentSession?.id && user && currentSession.host_id === user.id) {
              try { await LLAPI.launchSession(currentSession.id); }
              catch (err) { flash('Erreur : ' + err.message); return; }
            }
            goto('first-player');
          }}
          onTutorial={(g) => { if (g) setCurrentGame(g); goto('video'); }} />;
      case 'video':
        return <VideoScreen game={currentGame} onBack={() => goto('product')} />;
      case 'first-player':
        return <FirstPlayerScreen game={currentGame} session={currentSession} user={user} onBack={() => goto('product')} />;
      case 'product-shop':
        return <ProductShopScreen game={currentGame} onBack={() => goto('discover')}
          onNav={onNav} onOpenGame={openGameShop} />;
      case 'library':
        return <LibraryScreen onNav={onNav} onOpenGame={openGame}
          onScan={() => goto('scan')} />;
      case 'scan':
        return <ScanScreen onBack={() => goto('library')}
          onDetected={(g) => { setCurrentGame(g); goto('product'); }} />;
      case 'discover':
        return <DiscoverScreen onNav={onNav} onOpenGame={openGameShop} />;
      case 'profile':
        return <ProfileScreen onNav={onNav} onHistory={() => goto('history')}
          onFollowers={() => goto('followers')} onFollowing={() => goto('following')}
          user={user} onLogout={() => { LLAPI.logout(); setUser(null); goto('onboarding'); }} />;
      case 'followers':
        return <FollowListScreen mode="followers" userId={user?.id} onBack={() => goto('profile')} />;
      case 'following':
        return <FollowListScreen mode="following" userId={user?.id} onBack={() => goto('profile')} />;
      case 'history':
        return <HistoryScreen onBack={() => goto('profile')} onOpenGame={openGame} />;
      case 'feed':
        return <FeedScreen onBack={() => goto('new-session')} />;
      case 'home':
        return <FeedScreen onNav={onNav}
          onNotifications={() => goto('notifications')}
          onMessages={() => goto('messages')}
          onStartWithIdea={() => goto('library')}
          onStartSwipe={() => goto('new-session')} />;
      case 'notifications':
        return <NotificationsScreen onBack={() => goto('home')} />;
      case 'messages':
        return <MessagesScreen onBack={() => goto('home')} />;
      default:
        return <OnboardingScreen />;
    }
  }

  if (booting) {
    return (
      <div style={{
        position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
        background: LL.navyDeep, color: LL.cream, fontFamily: LL.fontBody,
      }}>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: 38, fontWeight: 800, letterSpacing: -0.8 }}>ludilove</div>
          <div style={{
            marginTop: 26, display: 'flex', gap: 14, justifyContent: 'center',
          }}>
            {[0, 1, 2].map(i => (
              <div key={i} style={{
                width: 44, height: 44,
                animation: `ll-dice-roll 1.4s cubic-bezier(.36,.07,.19,.97) infinite`,
                animationDelay: `${i * 0.18}s`,
              }}>
                <LoadingDie color={LL.cream} bg={LL.navy}/>
              </div>
            ))}
          </div>
        </div>
        <style>{`
          @keyframes ll-dice-roll {
            0%   { transform: translateY(0)     rotate(0deg); }
            25%  { transform: translateY(-22px) rotate(180deg); }
            50%  { transform: translateY(0)     rotate(360deg); }
            55%  { transform: translateY(0)     rotate(360deg) scaleY(0.85); }
            60%  { transform: translateY(0)     rotate(360deg) scaleY(1); }
            100% { transform: translateY(0)     rotate(360deg); }
          }
        `}</style>
      </div>
    );
  }

  return (
    <div style={{
      position: 'fixed', inset: 0,
      background: LL.cream,
      fontFamily: LL.fontBody,
      overflow: 'hidden',
      paddingTop: 'env(safe-area-inset-top)',
      paddingBottom: 'env(safe-area-inset-bottom)',
      paddingLeft: 'env(safe-area-inset-left)',
      paddingRight: 'env(safe-area-inset-right)',
    }}>
      {banner && (
        <div style={{
          position: 'fixed',
          top: 'calc(env(safe-area-inset-top) + 12px)',
          left: '50%', transform: 'translateX(-50%)',
          background: LL.navyDeep, color: LL.cream,
          padding: '10px 18px', borderRadius: 999, zIndex: 1000,
          fontSize: 13, fontWeight: 600, maxWidth: '90vw',
          boxShadow: '0 6px 18px rgba(0,0,0,0.3)',
        }}>{banner}</div>
      )}
      <style>{`
        input[type=range] {
          -webkit-appearance: none; appearance: none;
        }
        input[type=range]::-webkit-slider-thumb {
          -webkit-appearance: none; appearance: none;
          width: 22px; height: 22px; border-radius: 50%;
          background: ${LL.cream};
          border: 2.5px solid ${LL.navy};
          cursor: pointer;
          box-shadow: 0 2px 4px rgba(14,47,99,0.3);
        }
        input[type=range]::-moz-range-thumb {
          width: 22px; height: 22px; border-radius: 50%;
          background: ${LL.cream};
          border: 2.5px solid ${LL.navy};
          cursor: pointer;
          box-shadow: 0 2px 4px rgba(14,47,99,0.3);
        }
        input[type=range]::-webkit-slider-runnable-track {
          -webkit-appearance: none; appearance: none;
          background: transparent;
        }
      `}</style>
      <div style={{ width: '100%', height: '100%', position: 'relative' }}>
        {renderScreen()}
      </div>
    </div>
  );
}

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