// room-app.jsx — Pilot experience: simple join form + REST polling (no auth required)

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

const PILOT_API  = "/api/pilot";  // relative — proxied through :3001, works on any device
const ROOM_CODE  = "HERELY";
const POLL_MS    = 4000;   // refresh member list every 4 seconds
const HB_MS      = 20000;  // heartbeat every 20 seconds (server window is 24 h)

// ─── Mood definitions ────────────────────────────────────────────────────────
const MOODS = [
  { key: "lit",         label: "Lit 🔥",         color: "#FF5E3A", desc: "Energised, ready for anything"                 },
  { key: "mellow",      label: "Mellow 🌊",      color: "#4DA6FF", desc: "Relaxed, going with the flow"                  },
  { key: "magnetic",    label: "Magnetic ✨",    color: "#FFD700", desc: "Here to connect, drawing people in"            },
  { key: "present",     label: "Present 🎯",     color: "#00C49A", desc: "Fully in the moment, nowhere else to be"       },
  { key: "adventurous", label: "Adventurous 🌀", color: "#A855F7", desc: "Open to the unexpected, say yes to everything"  },
];
const PILOT_MOOD_BY_KEY = Object.fromEntries(MOODS.map(m => [m.key, m]));

// ─── Convert pilot sessions → SpatialMap format ──────────────────────────────
function membersToRoom(members, mySessionId) {
  if (!members.length) return { people: [], counts: {}, openToTalk: 0, mutual: 0 };

  function strHash(s) {
    let h = 2166136261;
    for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = (h * 16777619) >>> 0; }
    return h;
  }
  const PROXIMITY_BIAS = { lit: -0.08, mellow: 0.06, magnetic: -0.14, present: 0.00, adventurous: -0.06 };
  const STATUS_BY_MOOD = {
    lit:         ["lit up", "energy up", "let's go", "here and alive"],
    mellow:      ["in the flow", "taking it easy", "easygoing", "going with it"],
    magnetic:    ["here to connect", "come say hi", "drawing you in", "open to all"],
    present:     ["fully here", "in this moment", "nowhere else", "all in"],
    adventurous: ["saying yes", "open to anything", "on an adventure", "ready for whatever"],
  };

  // Exclude yourself — you are the nucleus (center white ball), not an electron
  const others = members.filter(m => m.sessionId !== mySessionId);

  const people = others.map((m, idx) => {
    const mood = PILOT_MOOD_BY_KEY[m.mood] ? m.mood : "lit";
    const meta = PILOT_MOOD_BY_KEY[mood];
    const h    = strHash(m.sessionId || m._id || String(idx));
    const r1   = ((h * 16777619)  >>> 0) / 4294967296;
    const r2   = ((h * 2166136261)>>> 0) / 4294967296;
    const r3   = ((h * 1000003)   >>> 0) / 4294967296;
    // Spread proximity from 0.15 to 0.85 so people land on different shells
    const prox = Math.min(0.85, Math.max(0.15, r1 * 0.70 + 0.15 + (PROXIMITY_BIAS[mood] || 0)));
    const sList = STATUS_BY_MOOD[mood] || STATUS_BY_MOOD.lit;

    return {
      id:        idx,  // numeric id required by SpatialEngine Int32Array
      mood,
      color:     meta.color,
      size:      (meta?.size || 1) * (0.85 + r2 * 0.30),
      seed:      r3,
      importance: 0,
      proximity: prox,
      name:      (m.name || "Someone").split(" ")[0],
      last:      (m.name || "").split(" ").slice(1).join(" ") || "",
      role:      "attendee",
      status:    sList[Math.floor(r1 * sList.length)],
      openTo:    "a conversation",
      tags:      [],
      mutual:    r3 < 0.12,
      sessionId: m.sessionId,
    };
  });

  const counts = {};
  for (const m of MOODS) counts[m.key] = 0;
  for (const p of people) counts[p.mood]++;
  // lit and magnetic are the high-energy social moods
  const openToTalk = people.filter(p => p.mood === "lit" || p.mood === "magnetic").length;
  const mutual     = people.filter(p => p.mutual).length;
  // totalPresent includes YOU
  return { people, counts, openToTalk, mutual, totalPresent: members.length };
}

// Export so scanqr.jsx MoodSelector picks up the right moods
if (typeof window !== 'undefined') window.MOODS = MOODS;


// ─── Icons ───────────────────────────────────────────────────────────────────
const Arrow = () => (
  <svg className="arrow" viewBox="0 0 14 14" fill="none">
    <path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>
);
const Close = () => (
  <svg viewBox="0 0 16 16" width="14" height="14" fill="none">
    <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
  </svg>
);

// ─── ID Card ─────────────────────────────────────────────────────────────────
function IDCard({ person, onClose }) {
  if (!person) return null;
  const col      = (PILOT_MOOD_BY_KEY[person.mood] || MOODS[0]).color;
  const moodMeta = PILOT_MOOD_BY_KEY[person.mood] || MOODS[0];
  const initial  = (person.name || "?").charAt(0).toUpperCase();
  return (
    <aside className="id-card" role="dialog">
      <button className="id-close" onClick={onClose}><Close/></button>
      <div className="id-avatar" style={{"--c": col}}>
        <div className="id-avatar-bg"></div>
        <div className="id-avatar-grain"></div>
        <div className="id-avatar-ring" aria-hidden="true">{[0,1,2].map(i=><span key={i} style={{"--i":i}}></span>)}</div>
        <span className="id-initial">{initial}</span>
        <span className="id-mood-pill"><span className="d" style={{background:col}}></span>{moodMeta.label}</span>
        <span className="id-presence"><span className="d"></span>Present · now</span>
      </div>
      <div className="id-body">
        <div className="id-head">
          <h3 className="id-name">{person.name}</h3>
          <p className="id-role" style={{color: col, opacity: 0.85}}>{moodMeta.label}</p>
        </div>
        <div className="id-meta">
          <div className="id-meta-row">
            <span className="id-meta-l">Vibe</span>
            <span className="id-meta-v">{moodMeta.desc}</span>
          </div>
          <div className="id-meta-row">
            <span className="id-meta-l">Status</span>
            <span className="id-meta-v">{person.status}</span>
          </div>
        </div>
        <div className="id-actions">
          <button className="btn btn-ghost id-btn-ghost" onClick={onClose}>Close</button>
        </div>
      </div>
    </aside>
  );
}

// ─── Join Form (shown when user hasn't entered their name yet) ────────────────
function JoinForm({ onJoined }) {
  const [name,    setName]    = useState("");
  const [contact, setContact] = useState("");
  const [mood,    setMood]    = useState("lit");
  const [loading, setLoading] = useState(false);
  const [error,   setError]   = useState(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!name.trim()) { setError("Please enter your name."); return; }
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(`${PILOT_API}/join`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name: name.trim(), contact: contact.trim(), roomCode: ROOM_CODE, mood }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.message || "Could not join room.");
      // Save session to localStorage
      localStorage.setItem("herely.pilot", JSON.stringify({ sessionId: data.sessionId, name: name.trim(), mood }));
      onJoined(data.sessionId, data.members || []);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <main style={{ minHeight:"100vh", display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", padding:"24px" }}>
      <div style={{
        width:"100%", maxWidth:480,
        background:"var(--bg-2, rgba(255,255,255,0.04))",
        border:"1px solid var(--line)",
        borderRadius:24, padding:"40px 36px",
      }}>
        {/* Header */}
        <div style={{ marginBottom:32 }}>
          <div style={{ fontFamily:"var(--mono)", fontSize:11, letterSpacing:".12em", textTransform:"uppercase", color:"var(--m-teal)", marginBottom:12, display:"flex", alignItems:"center", gap:6 }}>
            <span style={{ width:7, height:7, borderRadius:"50%", background:"var(--m-teal)", display:"inline-block", boxShadow:"0 0 0 3px rgba(0,196,154,.2)", animation:"breathe 3s ease-in-out infinite" }}></span>
            {ROOM_CODE} · Live now
          </div>
          <h1 style={{ fontSize:"clamp(28px,5vw,40px)", lineHeight:1.1, fontFamily:"var(--serif)", fontStyle:"italic", marginBottom:10 }}>
            Who's <em>here</em>, right now.
          </h1>
          <p style={{ color:"var(--mute)", fontSize:14, lineHeight:1.6 }}>
            Enter your name to join the room. You'll instantly appear on the map for everyone else here.
          </p>
        </div>

        <form onSubmit={handleSubmit} style={{ display:"flex", flexDirection:"column", gap:14 }}>
          {/* Name */}
          <div>
            <label style={{ display:"block", fontFamily:"var(--mono)", fontSize:11, letterSpacing:".10em", textTransform:"uppercase", color:"var(--mute)", marginBottom:6 }}>Your name</label>
            <input
              type="text"
              placeholder="e.g. Anya"
              value={name}
              onChange={e => setName(e.target.value)}
              autoFocus
              style={{
                width:"100%", padding:"13px 16px", borderRadius:12, boxSizing:"border-box",
                background:"var(--bg)", border:"1px solid var(--line)",
                color:"var(--fg)", fontSize:15, fontFamily:"var(--sans)",
                outline:"none", transition:"border-color .2s",
              }}
              onFocus={e => e.target.style.borderColor = "var(--m-teal)"}
              onBlur={e  => e.target.style.borderColor = "var(--line)"}
            />
          </div>

          {/* Email or phone (optional) */}
          <div>
            <label style={{ display:"block", fontFamily:"var(--mono)", fontSize:11, letterSpacing:".10em", textTransform:"uppercase", color:"var(--mute)", marginBottom:6 }}>
              Email or phone <span style={{ opacity:.5 }}>(optional)</span>
            </label>
            <input
              type="text"
              placeholder="so others can reach you"
              value={contact}
              onChange={e => setContact(e.target.value)}
              style={{
                width:"100%", padding:"13px 16px", borderRadius:12, boxSizing:"border-box",
                background:"var(--bg)", border:"1px solid var(--line)",
                color:"var(--fg)", fontSize:15, fontFamily:"var(--sans)",
                outline:"none", transition:"border-color .2s",
              }}
              onFocus={e => e.target.style.borderColor = "var(--m-teal)"}
              onBlur={e  => e.target.style.borderColor = "var(--line)"}
            />
          </div>

          {/* Mood picker */}
          <div>
            <label style={{ display:"block", fontFamily:"var(--mono)", fontSize:11, letterSpacing:".10em", textTransform:"uppercase", color:"var(--mute)", marginBottom:10 }}>
              What do you bring today?
            </label>
            <div style={{ display:"flex", gap:8, flexWrap:"wrap" }}>
              {MOODS.map(m => (
                <button
                  type="button"
                  key={m.key}
                  onClick={() => setMood(m.key)}
                  style={{
                    padding:"8px 14px", borderRadius:20, cursor:"pointer",
                    fontFamily:"var(--mono)", fontSize:11, letterSpacing:".08em",
                    border:`1.5px solid ${mood === m.key ? m.color : "var(--line)"}`,
                    background: mood === m.key ? m.color + "18" : "transparent",
                    color: mood === m.key ? m.color : "var(--mute)",
                    display:"flex", alignItems:"center", gap:6,
                    transition:"all .15s ease",
                  }}
                >
                  <span style={{ width:6, height:6, borderRadius:"50%", background:m.color, display:"inline-block" }}></span>
                  {m.label}
                </button>
              ))}
            </div>
          </div>

          {error && (
            <div style={{ padding:"10px 14px", borderRadius:10, background:"rgba(255,107,107,.1)", border:"1px solid rgba(255,107,107,.3)", color:"#FF6B6B", fontSize:13 }}>
              {error}
            </div>
          )}

          <button
            type="submit"
            disabled={loading}
            style={{
              marginTop:8, padding:"15px 24px", borderRadius:14,
              background: loading ? "var(--line)" : "var(--fg)",
              color: loading ? "var(--mute)" : "var(--bg)",
              fontFamily:"var(--mono)", fontSize:13, letterSpacing:".08em",
              border:"none", cursor: loading ? "not-allowed" : "pointer",
              display:"flex", alignItems:"center", justifyContent:"center", gap:8,
              transition:"all .2s ease",
            }}
          >
            {loading ? "Joining…" : <><span>Enter the room</span><Arrow/></>}
          </button>
        </form>
      </div>
    </main>
  );
}

// ─── Room View ────────────────────────────────────────────────────────────────
function RoomView({ sessionId, initialMembers, myName, myMood, onNavigate }) {
  const [members,    setMembers]    = useState(initialMembers || []);
  const [filter,     setFilter]     = useState("all");
  const [selectedId, setSelectedId] = useState(null);
  const [time, setTime] = useState(() =>
    new Date().toLocaleTimeString([], { hour:"2-digit", minute:"2-digit" })
  );
  const apiRef   = useRef(null);
  const pollRef  = useRef(null);
  const hbRef    = useRef(null);

  // Fetch latest members — only update state if list actually changed
  const fetchMembers = useCallback(async () => {
    try {
      const res  = await fetch(`${PILOT_API}/members?roomCode=${ROOM_CODE}`);
      const data = await res.json();
      if (data.members) {
        // FIX #5: compare sessionIds to avoid resetting camera every 4s
        setMembers(prev => {
          const prevIds = prev.map(m => m.sessionId).sort().join(',');
          const newIds  = data.members.map(m => m.sessionId).sort().join(',');
          return prevIds === newIds ? prev : data.members;
        });
      }
    } catch (_) {}
  }, []);

  // Heartbeat to stay alive
  const sendHeartbeat = useCallback(async () => {
    try {
      await fetch(`${PILOT_API}/heartbeat`, {
        method:"POST", headers:{"Content-Type":"application/json"},
        body: JSON.stringify({ sessionId }),
      });
    } catch (_) {}
  }, [sessionId]);

  useEffect(() => {
    // Poll immediately and every POLL_MS
    fetchMembers();
    pollRef.current = setInterval(fetchMembers, POLL_MS);
    hbRef.current   = setInterval(sendHeartbeat, HB_MS);

    // Clock
    const clock = setInterval(
      () => setTime(new Date().toLocaleTimeString([], { hour:"2-digit", minute:"2-digit" })),
      30000
    );

    // Keyboard
    const onKey = (e) => { if (e.key === "Escape") setSelectedId(null); };
    window.addEventListener("keydown", onKey);

    return () => {
      clearInterval(pollRef.current);
      clearInterval(hbRef.current);
      clearInterval(clock);
      window.removeEventListener("keydown", onKey);
    };
  }, [fetchMembers, sendHeartbeat, sessionId]);

  // Explicitly leave the room — called by Leave button and goHome
  const leaveRoom = useCallback(async () => {
    try {
      await fetch(`${PILOT_API}/leave`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ sessionId }),
        keepalive: true,
      });
    } catch (_) {}
    localStorage.removeItem("herely.pilot");
  }, [sessionId]);

  const room = useMemo(() => membersToRoom(members, sessionId), [members, sessionId]);
  const activeFilter = useMemo(() => filter === "all" ? null : new Set([filter]), [filter]);
  const selected = useMemo(() =>
    selectedId !== null && selectedId !== undefined
      ? room.people.find(p => p.id === selectedId) ?? null
      : null,
    [selectedId, room.people]
  );

  const goHome = async (e) => {
    e.preventDefault();
    await leaveRoom();           // ← actually remove from room in DB first
    if (onNavigate) onNavigate("/NYC51");
  };

  return (
    <>
      {/* Nav */}
      <nav className="nav">
        <div className="wrap nav-inner">
          <BrandLogo href="/NYC51" onClick={goHome} />
          <div className="nav-links">
            <a href="/NYC51" onClick={goHome}>Home</a>
          </div>
          <div className="nav-cta">
            <div className="nav-status">
              <span className="dot" style={{ background:"var(--m-teal)", boxShadow:"0 0 0 3px rgba(0,196,154,.2)", animation:"breathe 3s ease-in-out infinite" }}></span>
              {ROOM_CODE} · {members.length} present
            </div>
            <a href="/NYC51" onClick={goHome} className="btn btn-ghost">Leave room <Arrow/></a>
          </div>
        </div>
      </nav>

      <main className="room-page">
        <div className="wrap room-head">
          <div className="eyebrow">Room · {ROOM_CODE} · live</div>
          <h1 className="room-title">Who's <span className="ed">here</span>, right now.</h1>
          <p className="lede" style={{ marginTop:14, maxWidth:"50ch", fontSize:"15px" }}>
            Every ball is a real person in this room. They appear the moment they join.
          </p>
        </div>

        <div className="wrap">
          {/* Room map */}
          <div className="room-shell" style={{ marginBottom:24 }} data-selected={selected ? "true" : "false"}>
            <div className="room-stage">
              <div className="room-content">
                <div className="room-map">
                  <div className="radar-stage--lg" style={{ position:"relative", width:"100%", overflow:"hidden", border:"1px solid var(--line)", borderRadius:"24px", isolation:"isolate", transform:"translateZ(0)" }}>
                    <div className="stage-chrome">
                      <div className="left"><span className="dot"></span><span>{ROOM_CODE} · live</span></div>
                      <div className="right">{time} · {members.length} present</div>
                    </div>
                    <SpatialMap
                      room={room}
                      filter={activeFilter}
                      selectedId={selectedId}
                      onSelect={setSelectedId}
                      onLOD={() => {}}
                      onReshuffle={() => {}}
                      apiRef={apiRef}
                    />
                  </div>
                </div>

                <div className="room-readout">
                  <div>
                    <div className="mono" style={{ marginBottom:14 }}>Mood signals</div>
                    <div className="legend">
                      {MOODS.map(m => (
                        <div className="item" key={m.key}>
                          <span className="swatch" style={{ background:m.color, boxShadow:`0 0 0 4px ${m.color}22` }}></span>
                          <span style={{ minWidth:74 }}>{m.label}</span>
                          <span style={{ color:"var(--mute)" }}>{m.desc}</span>
                        </div>
                      ))}
                    </div>
                  </div>
                  <div>
                    <div className="mono" style={{ marginBottom:12 }}>Filter the room</div>
                    <div className="filter-row">
                      <button className={"filter" + (filter==="all"?" on":"")} onClick={()=>setFilter("all")}>All</button>
                      {MOODS.map(m => (
                        <button key={m.key} className={"filter"+(filter===m.key?" on":"")} onClick={()=>setFilter(m.key)}>
                          <span className="d" style={{background:m.color}}></span>{m.label}
                        </button>
                      ))}
                    </div>
                  </div>
                  <div>
                    <div className="mono" style={{ marginBottom:12 }}>Map controls</div>
                    <div style={{ display:"flex", gap:"8px" }}>
                      <button className="filter" onClick={() => apiRef.current?.resetView()}>Recenter</button>
                      <button className="filter" onClick={() => apiRef.current?.triggerReshuffle()}>Reshuffle</button>
                    </div>
                  </div>
                  <div style={{ marginTop:8, display:"flex", flexDirection:"column", gap:12 }}>
                    <div className="stat"><span className="v">{members.length}</span><span className="l">Present</span></div>
                    <div className="stat"><span className="v">{room.openToTalk}</span><span className="l">Open to talk</span></div>
                    <div className="stat"><span className="v">{room.mutual}</span><span className="l">Mutual signals</span></div>
                  </div>
                </div>
              </div>

              <div className="room-card-wrap" aria-hidden={!selected}>
                <IDCard person={selected} onClose={() => setSelectedId(null)}/>
              </div>
            </div>
          </div>

          {/* Presence strip */}
          <div style={{
            border:"1px solid var(--line)", borderRadius:20,
            background:"var(--bg-2, rgba(255,255,255,.03))",
            padding:"18px 22px 20px",
          }}>
            <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom: members.length ? 16 : 0 }}>
              <span style={{ fontSize:13, fontWeight:500 }}>Who's here right now</span>
              <span style={{ display:"inline-flex", alignItems:"center", gap:6, fontFamily:"var(--mono)", fontSize:10, letterSpacing:".10em", textTransform:"uppercase", color:"var(--mute)" }}>
                <span style={{ width:7, height:7, borderRadius:"50%", background:"var(--m-teal)", display:"inline-block", boxShadow:"0 0 0 3px rgba(0,196,154,.2)", animation:"breathe 3s ease-in-out infinite" }}></span>
                Live · {members.length} present
              </span>
            </div>
            {members.length === 0 ? (
              <div style={{ color:"var(--mute)", fontSize:13, fontStyle:"italic" }}>No one else yet — you're first!</div>
            ) : (
              <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(140px,1fr))", gap:10 }}>
                {members.map(m => {
                  const moodKey = PILOT_MOOD_BY_KEY[m.mood] ? m.mood : "lit";
                  const meta = PILOT_MOOD_BY_KEY[moodKey];
                  const color = meta.color;
                  const isMe  = m.sessionId === sessionId;
                  const isSelected = selected && selected.sessionId === m.sessionId;
                  return (
                    <div
                      key={m.sessionId || m._id}
                      onClick={() => {
                        if (isMe) return;
                        const person = room.people.find(p => p.sessionId === m.sessionId);
                        if (person) setSelectedId(person.id);
                      }}
                      style={{
                        display:"flex", alignItems:"center", gap:10, padding:"10px 13px",
                        borderRadius:13,
                        border: isMe
                          ? "1px solid var(--m-teal)"
                          : (isSelected
                             ? `1.5px solid ${color}`
                             : "1px solid var(--line)"),
                        background: isSelected ? `${color}0c` : "var(--bg)",
                        cursor: !isMe ? "pointer" : "default",
                        boxShadow: isSelected ? `0 0 12px ${color}1a` : "none",
                        transition: "all 0.2s ease",
                      }}
                    >
                      <div style={{
                        width:32, height:32, borderRadius:"50%", flexShrink:0,
                        display:"flex", alignItems:"center", justifyContent:"center",
                        background: color + "20", color, fontSize:16, fontFamily:"var(--serif)", fontStyle:"italic",
                        border:`1px solid ${color}44`,
                      }}>
                        {(m.name || "?").charAt(0).toUpperCase()}
                      </div>
                      <div style={{ minWidth:0 }}>
                        <div style={{ fontSize:13, fontWeight:500, whiteSpace:"nowrap", overflow:"hidden", textOverflow:"ellipsis" }}>{m.name}</div>
                        <div style={{ display:"flex", alignItems:"center", gap:5, marginTop:2 }}>
                          <span style={{ width:6, height:6, borderRadius:"50%", background:color, display:"inline-block" }}></span>
                          <span style={{ fontFamily:"var(--mono)", fontSize:10, letterSpacing:".06em", textTransform:"uppercase", color:"var(--mute)" }}>{meta.label}</span>
                        </div>
                        {isMe && <div style={{ fontFamily:"var(--mono)", fontSize:9, letterSpacing:".10em", textTransform:"uppercase", color:"var(--m-teal)", marginTop:1 }}>You</div>}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        </div>
      </main>
    </>
  );
}

// ─── Root: RoomPage — decide join form or room view ──────────────────────────
function RoomPage({ onNavigate }) {
  const [phase, setPhase] = useState("loading"); // loading | join | room
  const [sessionId, setSessionId] = useState(null);
  const [members,   setMembers]   = useState([]);
  const [myName,    setMyName]    = useState("");
  const [myMood,    setMyMood]    = useState("lit");

  useEffect(() => {
    // Check if already joined this session
    const saved = JSON.parse(localStorage.getItem("herely.pilot") || "null");
    if (saved?.sessionId) {
      // Show room immediately with saved data, then update via API
      setSessionId(saved.sessionId);
      setMyName(saved.name || "");
      setMyMood(saved.mood || "lit");
      setPhase("room");

      // Re-join in background to refresh lastSeen and get latest members
      fetch(`${PILOT_API}/join`, {
        method:"POST", headers:{"Content-Type":"application/json"},
        body: JSON.stringify({
          sessionId: saved.sessionId,
          name: saved.name || "Guest",
          roomCode: ROOM_CODE,
          mood: saved.mood || "lit",
        }),
      })
        .then(r => r.json())
        .then(data => { if (data.members) setMembers(data.members); })
        .catch(() => {});
    } else {
      window.location.replace(`/NYC51`);
    }
  }, []);

  const handleJoined = (sid, initialMembers) => {
    setSessionId(sid);
    setMembers(initialMembers);
    const saved = JSON.parse(localStorage.getItem("herely.pilot") || "{}");
    setMyName(saved.name || "");
    setMyMood(saved.mood || "lit");
    setPhase("room");
  };

  if (phase === "loading") {
    return (
      <div style={{ minHeight:"100vh", display:"flex", alignItems:"center", justifyContent:"center", color:"var(--mute)", fontFamily:"var(--mono)", fontSize:12, letterSpacing:".10em", textTransform:"uppercase" }}>
        Loading…
      </div>
    );
  }

  if (phase === "join") {
    return <JoinForm onJoined={handleJoined} />;
  }

  return (
    <RoomView
      sessionId={sessionId}
      initialMembers={members}
      myName={myName}
      myMood={myMood}
      onNavigate={onNavigate}
    />
  );
}

// RoomPage is mounted by app.jsx's router at /room/* routes.
