/* Pyramid · main app */

const ACCENT_PRESETS = [
  { name: 'amber',  h: 42,  s: 95, l: 58 },
  { name: 'coral',  h: 12,  s: 85, l: 62 },
  { name: 'mint',   h: 160, s: 65, l: 50 },
  { name: 'violet', h: 268, s: 78, l: 66 },
  { name: 'cobalt', h: 220, s: 85, l: 62 },
  { name: 'lime',   h: 80,  s: 70, l: 55 },
];

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accentIdx": 0,
  "theme": "dark",
  "density": 1,
  "motion": 1,
  "radius": 12,
  "view": "chat"
}/*EDITMODE-END*/;

const loadTweak = (k, d) => {
  try { const v = localStorage.getItem('pyr_' + k); return v === null ? d : JSON.parse(v); } catch { return d; }
};
const saveTweak = (k, v) => { try { localStorage.setItem('pyr_' + k, JSON.stringify(v)); } catch {} };

const DEFAULT_CALL_PARTICIPANTS = [
  { name: 'juno', avatar: 'J', color: '#06b6d4', speaking: true, muted: false, cam: false },
  { name: 'sachi', avatar: 'S', color: '#a855f7', speaking: false, muted: false, cam: false },
  { name: 'mira (you)', avatar: 'M', color: '#ff6b9d', speaking: false, muted: false, cam: false, self: true },
  { name: 'ren', avatar: 'R', color: '#10b981', speaking: false, muted: true, cam: false },
];

const App = () => {
  const [theme, setTheme] = React.useState(() => loadTweak('theme', TWEAK_DEFAULTS.theme));
  const [accentIdx, setAccentIdx] = React.useState(() => loadTweak('accentIdx', TWEAK_DEFAULTS.accentIdx));
  const [density, setDensity] = React.useState(() => loadTweak('density', TWEAK_DEFAULTS.density));
  const [motion, setMotion] = React.useState(() => loadTweak('motion', TWEAK_DEFAULTS.motion));
  const [radius, setRadius] = React.useState(() => loadTweak('radius', TWEAK_DEFAULTS.radius));

  const [loggedIn, setLoggedIn] = React.useState(() => loadTweak('loggedIn', true));
  const [view, setView] = React.useState(() => {
    // never land on voice without an active call
    const v = loadTweak('view', 'chat');
    return v === 'voice' ? 'chat' : v;
  });
  const [activeSpace, setActiveSpace] = React.useState(() => loadTweak('space', 'atelier'));
  const [activeRoom, setActiveRoom] = React.useState(() => loadTweak('room', 'general'));
  const [railCollapsed, setRailCollapsed] = React.useState(false);
  const [membersOpen, setMembersOpen] = React.useState(true);
  const [tweaksMode, setTweaksMode] = React.useState(false);

  const [showSettings, setShowSettings] = React.useState(false);
  const [showSearch, setShowSearch] = React.useState(false);
  const [profilePopover, setProfilePopover] = React.useState(null);
  const [emojiPickerAt, setEmojiPickerAt] = React.useState(null);
  const [messageActions, setMessageActions] = React.useState(null);
  const [toast, setToast] = React.useState(null);

  const [messagesState, setMessagesState] = React.useState(() => window.PYRAMID_DATA.messagesByRoom);

  /* call state — persists across navigation */
  const [call, setCall] = React.useState(null);
  const [callReturnRoom, setCallReturnRoom] = React.useState(null);

  React.useEffect(() => { saveTweak('theme', theme); }, [theme]);
  React.useEffect(() => { saveTweak('accentIdx', accentIdx); }, [accentIdx]);
  React.useEffect(() => { saveTweak('density', density); }, [density]);
  React.useEffect(() => { saveTweak('motion', motion); }, [motion]);
  React.useEffect(() => { saveTweak('radius', radius); }, [radius]);
  React.useEffect(() => { saveTweak('view', view); }, [view]);
  React.useEffect(() => { saveTweak('space', activeSpace); }, [activeSpace]);
  React.useEffect(() => { saveTweak('room', activeRoom); }, [activeRoom]);
  React.useEffect(() => { saveTweak('loggedIn', loggedIn); }, [loggedIn]);

  React.useEffect(() => {
    const a = ACCENT_PRESETS[accentIdx];
    const r = document.documentElement;
    r.setAttribute('data-theme', theme);
    r.style.setProperty('--accent-h', a.h);
    r.style.setProperty('--accent-s', a.s + '%');
    r.style.setProperty('--accent-l', a.l + '%');
    r.style.setProperty('--density', density);
    r.style.setProperty('--motion', motion);
    r.style.setProperty('--r-base', radius + 'px');
  }, [theme, accentIdx, density, motion, radius]);

  React.useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode') setTweaksMode(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksMode(false);
    };
    window.addEventListener('message', handler);
    window.parent?.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  const pushEdits = (edits) => {
    try { window.parent?.postMessage({ type: '__edit_mode_set_keys', edits }, '*'); } catch {}
  };

  React.useEffect(() => {
    const h = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setShowSearch(true); }
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'b') { e.preventDefault(); setRailCollapsed(v => !v); }
      if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === 'u') { e.preventDefault(); setMembersOpen(v => !v); }
      if (e.key === 'Escape') {
        setShowSearch(false); setShowSettings(false);
        setProfilePopover(null); setEmojiPickerAt(null); setMessageActions(null);
      }
    };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, []);

  const showToast = (msg, icon = 'check') => {
    setToast({ msg, icon });
    setTimeout(() => setToast(null), 2400);
  };

  const handleSelectSpace = (spaceId) => {
    setActiveSpace(spaceId);
    setView('chat');
    const data = window.PYRAMID_DATA.rooms[spaceId];
    if (data) {
      const firstActive = data.sections.flatMap(s => s.rooms).find(r => r.active) || data.sections[0].rooms[0];
      setActiveRoom(firstActive.id);
    }
  };

  const handleSelectRoom = (roomId) => {
    setActiveRoom(roomId);
    const data = window.PYRAMID_DATA.rooms[activeSpace];
    const roomDef = data?.sections.flatMap(s => s.rooms).find(r => r.id === roomId);
    if (roomDef?.type === 'voice') {
      // joining a voice room starts a call for that room
      startCall({ roomName: roomDef.name, kind: 'voice', room: roomDef });
      setView('voice');
    } else {
      setView('chat');
    }
  };

  const startCall = ({ roomName, kind, room }) => {
    setCall({
      active: true,
      roomName,
      kind,
      participants: DEFAULT_CALL_PARTICIPANTS,
      mic: true, cam: kind === 'video', deaf: false,
      streaming: false, streamCollapsed: false,
      streamer: 'mira (you)',
      roomId: room?.id || null,
    });
    setCallReturnRoom({ space: activeSpace, room: activeRoom });
  };

  /* called from DM header */
  React.useEffect(() => {
    window.__startDMCall = (roomDef, kind) => {
      startCall({ roomName: roomDef?.name || 'DM', kind, room: roomDef });
      setView('voice');
    };
    return () => { window.__startDMCall = null; };
  }, [activeSpace, activeRoom]);

  const handleLeaveCall = () => {
    setCall(null);
    if (view === 'voice') {
      if (callReturnRoom) {
        setActiveSpace(callReturnRoom.space);
        setActiveRoom(callReturnRoom.room);
      }
      setView('chat');
    }
    setCallReturnRoom(null);
    showToast('left the call', 'phoneOff');
  };

  const updateCall = (patch) => setCall(c => c ? { ...c, ...patch } : c);

  const handleJumpToCall = () => {
    setView('voice');
  };

  const handleSend = (text) => {
    const newMsg = {
      id: 'm' + Date.now(),
      author: 'mira',
      avatar: 'M',
      color: '#ff6b9d',
      time: new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }),
      text,
    };
    setMessagesState(prev => ({
      ...prev,
      [activeRoom]: [...(prev[activeRoom] || []), newMsg],
    }));
  };

  const handleReact = (msgId, emoji) => {
    setMessagesState(prev => {
      const list = [...(prev[activeRoom] || [])];
      const idx = list.findIndex(m => m.id === msgId);
      if (idx < 0) return prev;
      const msg = { ...list[idx] };
      const reactions = [...(msg.reactions || [])];
      const existing = reactions.findIndex(r => r.emoji === emoji);
      if (existing >= 0) {
        const r = { ...reactions[existing] };
        if (r.mine) { r.mine = false; r.count--; } else { r.mine = true; r.count++; }
        if (r.count <= 0) reactions.splice(existing, 1);
        else reactions[existing] = r;
      } else {
        reactions.push({ emoji, count: 1, mine: true });
      }
      msg.reactions = reactions;
      list[idx] = msg;
      return { ...prev, [activeRoom]: list };
    });
  };

  const handleOpenProfile = (name, e) => {
    const rect = e?.currentTarget?.getBoundingClientRect();
    const profiles = {
      juno: { name: 'juno', handle: '@juno:pyramid.chat', avatar: 'J', color: '#06b6d4', status: 'online', about: 'risograph, zines, tea. teaches at the atelier on tuesdays.', roles: [{ name: 'founder', color: '#f59e0b' }, { name: 'print-nerd', color: '#06b6d4' }] },
      sachi: { name: 'sachi', handle: '@sachi:pyramid.chat', avatar: 'S', color: '#a855f7', status: 'online', about: 'illustration, collage, usually reading', roles: [{ name: 'mod', color: '#a855f7' }] },
      ren: { name: 'ren', handle: '@ren:pyramid.chat', avatar: 'R', color: '#10b981', status: 'busy', about: 'graphic design studio of one', roles: [] },
      kai: { name: 'kai', handle: '@kai:pyramid.chat', avatar: 'K', color: '#f43f5e', status: 'away', about: '3d + motion. fancy renders upon request.', roles: [] },
      ezra: { name: 'ezra', handle: '@ezra:pyramid.chat', avatar: 'E', color: '#3b82f6', status: 'online', about: 'keeps the lights on. dev-lab lurker.', roles: [{ name: 'dev', color: '#3b82f6' }] },
      mira: { name: 'mira', handle: '@mira:pyramid.chat', avatar: 'M', color: '#ff6b9d', status: 'online', about: 'painter · printmaker · pastry enthusiast', roles: [{ name: 'founder', color: '#f59e0b' }] },
    };
    setProfilePopover({ anchor: rect, profile: profiles[name] || profiles.juno });
  };

  const handleOpenEmoji = (target, e) => {
    const rect = e?.currentTarget?.getBoundingClientRect();
    setEmojiPickerAt({ target, rect });
  };

  const handlePickEmoji = (emoji) => {
    if (emojiPickerAt?.target === 'composer') {
      showToast(`${emoji} added`, 'check');
    } else if (emojiPickerAt?.target) {
      handleReact(emojiPickerAt.target, emoji);
    }
  };

  const handleOpenActions = (msgId, e) => {
    const rect = e?.currentTarget?.getBoundingClientRect();
    setMessageActions({ msgId, rect });
  };

  const handleMsgAction = (action) => {
    const labels = {
      reply: 'replying…', thread: 'thread opened', edit: 'editing message',
      pin: 'pinned to room', bookmark: 'saved for later',
      copy: 'copied', link: 'message link copied', delete: 'message deleted',
    };
    showToast(labels[action] || action);
  };

  if (!loggedIn) {
    return <LoginScreen onLogin={() => setLoggedIn(true)} />;
  }

  const spaces = window.PYRAMID_DATA.spaces;
  const roomsData = window.PYRAMID_DATA.rooms[activeSpace] || window.PYRAMID_DATA.rooms.atelier;
  const messages = messagesState[activeRoom] || [];
  const members = window.PYRAMID_DATA.membersByRoom[activeRoom] || window.PYRAMID_DATA.membersByRoom.general;

  const showMembers = membersOpen && view !== 'voice';

  const appClasses = [
    'app',
    railCollapsed && 'rail-collapsed',
    showMembers && 'right-open',
  ].filter(Boolean).join(' ');

  return (
    <>
      <div className={appClasses} data-screen-label={view === 'voice' ? 'Voice Channel' : activeRoom}>
        <SpacesRail
          spaces={spaces}
          activeSpace={activeSpace}
          onSelect={handleSelectSpace}
          collapsed={railCollapsed}
        />
        <RoomsPanel
          space={activeSpace}
          roomsData={roomsData}
          activeRoom={activeRoom}
          onSelectRoom={handleSelectRoom}
          user={window.PYRAMID_DATA.user}
          onOpenProfile={(e) => handleOpenProfile('mira', e)}
          onOpenSettings={() => setShowSettings(true)}
          call={call}
          onLeaveCall={handleLeaveCall}
          onToggleStreamCollapse={() => call && updateCall({ streamCollapsed: !call.streamCollapsed })}
          onToggleMic={() => call && updateCall({ mic: !call.mic })}
          onToggleDeaf={() => call && updateCall({ deaf: !call.deaf })}
          onToggleScreen={() => call && updateCall({ streaming: !call.streaming, streamCollapsed: false })}
          onToggleCam={() => call && updateCall({ cam: !call.cam })}
          onJumpToCall={handleJumpToCall}
        />
        {view === 'voice' ? (
          <VoiceChannel
            call={call}
            onLeave={handleLeaveCall}
            onToggleRail={() => setRailCollapsed(v => !v)}
            onOpenProfile={handleOpenProfile}
            onToggleMic={() => call && updateCall({ mic: !call.mic })}
            onToggleDeaf={() => call && updateCall({ deaf: !call.deaf })}
            onToggleCam={() => call && updateCall({ cam: !call.cam })}
            onToggleScreen={() => call && updateCall({ streaming: !call.streaming, streamCollapsed: false })}
          />
        ) : (
          <ChatView
            room={activeRoom}
            roomsData={roomsData}
            messages={messages}
            members={members}
            onOpenProfile={handleOpenProfile}
            onOpenActions={handleOpenActions}
            onOpenEmoji={handleOpenEmoji}
            onToggleMembers={() => setMembersOpen(v => !v)}
            membersOpen={membersOpen}
            onOpenSearch={() => setShowSearch(true)}
            onToggleRail={() => setRailCollapsed(v => !v)}
            railCollapsed={railCollapsed}
            onSend={handleSend}
            onReact={handleReact}
          />
        )}
        {showMembers && <MembersPanel room={activeRoom} members={members} />}
      </div>

      <DemoSwitcher
        view={view}
        setView={(v) => {
          if (v === 'voice') {
            if (!call) startCall({ roomName: 'The Lounge', kind: 'voice', room: { id: 'lounge', name: 'The Lounge' } });
            setView('voice');
          }
          else if (v === 'dm') { setActiveSpace('friends'); setActiveRoom('dm-juno'); setView('chat'); }
          else if (v === 'chat') { setActiveSpace('atelier'); setActiveRoom('general'); setView('chat'); }
        }}
        onLogin={() => setLoggedIn(false)}
        onSearch={() => setShowSearch(true)}
        onSettings={() => setShowSettings(true)}
        onProfile={(e) => handleOpenProfile('juno', e)}
        onEmoji={(e) => handleOpenEmoji('composer', e)}
        onTheme={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}
        theme={theme}
      />

      {showSettings && (
        <SettingsModal
          onClose={() => setShowSettings(false)}
          theme={theme}
          onTheme={setTheme}
          accentPresets={ACCENT_PRESETS}
          accent={ACCENT_PRESETS[accentIdx].h}
          onAccent={(p) => setAccentIdx(ACCENT_PRESETS.findIndex(a => a.name === p.name))}
          density={density}
          onDensity={setDensity}
          motion={motion}
          onMotion={setMotion}
          radius={radius}
          onRadius={setRadius}
        />
      )}
      {showSearch && <SearchModal onClose={() => setShowSearch(false)} onJump={() => setShowSearch(false)} />}
      {profilePopover && (
        <ProfilePopover
          anchor={profilePopover.anchor}
          profile={profilePopover.profile}
          onClose={() => setProfilePopover(null)}
        />
      )}
      {emojiPickerAt && (
        <EmojiPicker
          anchor={emojiPickerAt.rect}
          onPick={handlePickEmoji}
          onClose={() => setEmojiPickerAt(null)}
        />
      )}
      {messageActions && (
        <MessageActionsMenu
          anchor={messageActions.rect}
          onAction={handleMsgAction}
          onClose={() => setMessageActions(null)}
        />
      )}
      {toast && (
        <div className="toast">
          <Icon name={toast.icon} size={14} />
          <span>{toast.msg}</span>
        </div>
      )}

      {tweaksMode && (
        <TweaksPanel
          theme={theme} setTheme={(v) => { setTheme(v); pushEdits({ theme: v }); }}
          accentIdx={accentIdx} setAccentIdx={(v) => { setAccentIdx(v); pushEdits({ accentIdx: v }); }}
          density={density} setDensity={(v) => { setDensity(v); pushEdits({ density: v }); }}
          motion={motion} setMotion={(v) => { setMotion(v); pushEdits({ motion: v }); }}
          radius={radius} setRadius={(v) => { setRadius(v); pushEdits({ radius: v }); }}
        />
      )}
    </>
  );
};

const DemoSwitcher = ({ view, setView, onLogin, onSearch, onSettings, onProfile, onEmoji, onTheme, theme }) => {
  return (
    <div className="demo-switcher">
      <button className={view === 'chat' ? 'active' : ''} onClick={() => setView('chat')}>Chat</button>
      <button className={view === 'dm' ? 'active' : ''} onClick={() => setView('dm')}>DM</button>
      <button className={view === 'voice' ? 'active' : ''} onClick={() => setView('voice')}>Voice</button>
      <div style={{width: 1, background: 'var(--border)', margin: '4px 2px'}} />
      <button onClick={(e) => onProfile(e)}>Profile</button>
      <button onClick={(e) => onEmoji(e)}>Emoji</button>
      <button onClick={onSearch}>Search</button>
      <button onClick={onSettings}>Settings</button>
      <button onClick={onLogin}>Login</button>
      <div style={{width: 1, background: 'var(--border)', margin: '4px 2px'}} />
      <button onClick={onTheme} title="Toggle theme">
        <Icon name={theme === 'dark' ? 'sun' : 'moon'} size={12} />
      </button>
    </div>
  );
};

const TweaksPanel = ({ theme, setTheme, accentIdx, setAccentIdx, density, setDensity, motion, setMotion, radius, setRadius }) => (
  <div className="tweaks-panel">
    <div className="tweaks-header">
      <div className="tweaks-title"><Icon name="sparkle" size={14} /> Tweaks</div>
      <span style={{fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'var(--font-mono)'}}>pyramid.sys</span>
    </div>
    <div className="tweaks-body">
      <div className="tweak-row">
        <div className="tweak-label"><span>Theme</span><span className="val">{theme}</span></div>
        <div className="seg">
          <button className={theme === 'dark' ? 'active' : ''} onClick={() => setTheme('dark')}>Dark</button>
          <button className={theme === 'light' ? 'active' : ''} onClick={() => setTheme('light')}>Light</button>
        </div>
      </div>
      <div className="tweak-row">
        <div className="tweak-label"><span>Accent</span><span className="val">{ACCENT_PRESETS[accentIdx].name}</span></div>
        <div className="tweak-swatches">
          {ACCENT_PRESETS.map((p, i) => (
            <div key={p.name} className={`tweak-swatch ${accentIdx === i ? 'active' : ''}`}
              style={{ background: `hsl(${p.h} ${p.s}% ${p.l}%)` }}
              onClick={() => setAccentIdx(i)} title={p.name} />
          ))}
        </div>
      </div>
      <div className="tweak-row">
        <div className="tweak-label"><span>Density</span><span className="val">{density === 0.85 ? 'compact' : density === 1.2 ? 'cozy' : 'default'}</span></div>
        <div className="seg">
          <button className={density === 0.85 ? 'active' : ''} onClick={() => setDensity(0.85)}>Compact</button>
          <button className={density === 1 ? 'active' : ''} onClick={() => setDensity(1)}>Default</button>
          <button className={density === 1.2 ? 'active' : ''} onClick={() => setDensity(1.2)}>Cozy</button>
        </div>
      </div>
      <div className="tweak-row">
        <div className="tweak-label"><span>Corner radius</span><span className="val">{radius}px</span></div>
        <input type="range" min="4" max="20" value={radius} onChange={e => setRadius(+e.target.value)} />
      </div>
      <div className="tweak-row">
        <div className="tweak-label"><span>Motion</span><span className="val">{Math.round(motion*100)}%</span></div>
        <input type="range" min="0" max="100" value={motion*100} onChange={e => setMotion(+e.target.value/100)} />
      </div>
    </div>
  </div>
);

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