// Teilnehmer im Videocall — echte WebRTC-Verbindung via LiveKit Cloud,
// fliegende Emoji-Reaktionen werden über den Data-Channel verteilt.

const EMOJIS = [
  { e: '👏', label: 'Klatschen' },
  { e: '😊', label: 'Freude' },
  { e: '❤️', label: 'Liebe' },
  { e: '👍', label: 'Ja, gut' },
  { e: '👎', label: 'Nein, nicht gut' },
  { e: '🤔', label: 'Ich denke nach' },
  { e: '🎉', label: 'Hurra' },
  { e: '🤗', label: 'Schön, dich zu sehen' },
];

// Deterministische Pastelltöne für die Avatar-Fallbacks der Remote-Teilnehmer
const TILE_COLORS = ['#FFE4B5', '#F8D9D9', '#DCE7F8', '#D4F0DC', '#FFD0D0', '#E8E0F8'];
const colorFor = (identity) => {
  let h = 0;
  for (let i = 0; i < identity.length; i++) h = (h * 31 + identity.charCodeAt(i)) >>> 0;
  return TILE_COLORS[h % TILE_COLORS.length];
};

function VideoCall({ connection, meeting, onLeave, isModerator = false }) {
  const [micOn, setMicOn] = React.useState(true);
  const [camOn, setCamOn] = React.useState(true);
  const [reactions, setReactions] = React.useState([]);
  const [sideTab, setSideTab] = React.useState(isModerator ? 'tools' : 'people');
  const [elapsed, setElapsed] = React.useState(0);
  const [camError, setCamError] = React.useState(null);

  // LiveKit-Verbindung
  const [room, setRoom] = React.useState(null);
  const [conn, setConn] = React.useState('connecting'); // 'connecting' | 'connected' | 'error'
  const [connErr, setConnErr] = React.useState(null);
  const [pauseUntil, setPauseUntil] = React.useState(0); // ms-timestamp, > Date.now() = Pause aktiv
  const [displayedTitle, setDisplayedTitle] = React.useState(meeting?.title || 'Treffen');
  // forceRender wird auf jedes relevante Room-Event hin getriggert,
  // damit die JSX die aktuellen Track-/Speaker-Werte vom Room-Objekt liest
  const [, forceRender] = React.useReducer(x => x + 1, 0);

  // Live-Zähler im Call
  React.useEffect(() => {
    const t = setInterval(() => setElapsed(e => e + 1), 1000);
    return () => clearInterval(t);
  }, []);

  // Verbindung zur LiveKit Cloud — einmalig beim Mount, mit den
  // übergebenen Connection-Daten (url + token vom Backend gemintet)
  React.useEffect(() => {
    const LK = window.LivekitClient;
    if (!LK) {
      setConn('error');
      setConnErr('LiveKit-Bibliothek nicht geladen');
      return;
    }
    if (!connection?.url || !connection?.token) {
      setConn('error');
      setConnErr('Keine Verbindungs-Daten');
      return;
    }
    let canceled = false;
    let r = null;

    (async () => {
      try {
        r = new LK.Room({
          adaptiveStream: true,
          dynacast: true,
          videoCaptureDefaults: { facingMode: 'user' },
        });

        const onAny = () => { if (!canceled) forceRender(); };
        r.on(LK.RoomEvent.ParticipantConnected, onAny);
        r.on(LK.RoomEvent.ParticipantDisconnected, onAny);
        r.on(LK.RoomEvent.TrackSubscribed, onAny);
        r.on(LK.RoomEvent.TrackUnsubscribed, onAny);
        r.on(LK.RoomEvent.TrackPublished, onAny);
        r.on(LK.RoomEvent.TrackUnpublished, onAny);
        r.on(LK.RoomEvent.TrackMuted, onAny);
        r.on(LK.RoomEvent.TrackUnmuted, onAny);
        r.on(LK.RoomEvent.ActiveSpeakersChanged, onAny);
        r.on(LK.RoomEvent.LocalTrackPublished, onAny);
        r.on(LK.RoomEvent.LocalTrackUnpublished, onAny);
        r.on(LK.RoomEvent.Disconnected, (reason) => {
          if (canceled) return;
          const DR = LK.DisconnectReason || {};
          // Raum vom Moderator geschlossen / Teilnehmer entfernt → Treffen ist zu Ende
          const ended = reason === DR.ROOM_DELETED
                     || reason === DR.PARTICIPANT_REMOVED
                     || reason === DR.SERVER_SHUTDOWN;
          if (ended) {
            setConn('ended');
            setTimeout(() => { if (!canceled) onLeave && onLeave(); }, 4000);
          } else {
            setConn('error');
            setConnErr('Verbindung getrennt');
          }
        });
        // Eingehende Daten: Emojis + Pause-Signal. Bei Emojis die
        // Sender-Identität mitgeben, damit es an dessen Kachel erscheint.
        r.on(LK.RoomEvent.DataReceived, (payload, participant) => {
          try {
            const msg = JSON.parse(new TextDecoder().decode(payload));
            if (msg?.type === 'emoji' && msg.emoji) {
              addReactionLocal(msg.emoji, participant?.identity || 'unknown');
            } else if (msg?.type === 'pause') {
              setPauseUntil(Date.now() + 8000);
            }
          } catch { /* ignore */ }
        });
        // Server-seitig geänderter Titel
        r.on(LK.RoomEvent.RoomMetadataChanged, (newMetadata) => {
          try {
            const meta = JSON.parse(newMetadata);
            if (meta?.title) setDisplayedTitle(meta.title);
          } catch { /* ignore */ }
        });

        await r.connect(connection.url, connection.token);
        if (canceled) { r.disconnect(); return; }

        try {
          await r.localParticipant.setMicrophoneEnabled(true);
          await r.localParticipant.setCameraEnabled(true);
          setCamError(null);
        } catch (e) {
          console.warn('Media-Setup:', e?.name, e?.message);
          setCamError(
            e?.name === 'NotAllowedError' ? 'Zugriff verweigert'
            : e?.name === 'NotFoundError' ? 'Keine Kamera gefunden'
            : 'Kamera nicht verfügbar'
          );
        }

        setRoom(r);
        setConn('connected');
        forceRender();
      } catch (e) {
        console.error('LiveKit-Connect:', e);
        if (!canceled) {
          setConn('error');
          setConnErr(e?.message || 'Verbindung fehlgeschlagen');
        }
      }
    })();

    return () => {
      canceled = true;
      if (r) {
        try { r.disconnect(); } catch { /* ignore */ }
      }
    };
  }, []);

  // Mic-Toggle → LiveKit. Schlaegt das Einschalten fehl (z.B. Rechte
  // mitten im Call entzogen), Zustand zuruecksetzen — sonst zeigt der
  // Knopf "an", waehrend alle anderen ein stummes Mikro sehen.
  React.useEffect(() => {
    if (room && room.localParticipant) {
      room.localParticipant.setMicrophoneEnabled(micOn).catch(() => {
        if (micOn) setMicOn(false);
      });
    }
  }, [room, micOn]);

  // Kamera-Toggle → LiveKit (gleiches Prinzip wie beim Mikro)
  React.useEffect(() => {
    if (room && room.localParticipant) {
      room.localParticipant.setCameraEnabled(camOn).catch((e) => {
        if (e?.name === 'NotAllowedError') setCamError('Zugriff verweigert');
        if (camOn) setCamOn(false);
      });
    }
  }, [room, camOn]);

  // Reaktion lokal anzeigen — dem Fenster des Senders zugeordnet (senderId).
  // Leichter Zufalls-Offset + Rotation, damit's verspielt aussieht.
  // Timer werden getrackt und beim Unmount aufgeraeumt.
  const reactionTimers = React.useRef(new Set());
  const addReactionLocal = (emoji, senderId) => {
    const id = Math.random().toString(36).slice(2);
    const offset = 28 + Math.random() * 44;   // horizontale Position innerhalb der Kachel (%)
    const tilt = -10 + Math.random() * 20;    // leichte Kippung
    setReactions(r => [...r, { id, emoji, senderId, offset, tilt }]);
    const t = setTimeout(() => {
      reactionTimers.current.delete(t);
      setReactions(r => r.filter(x => x.id !== id));
    }, 2600);
    reactionTimers.current.add(t);
  };
  React.useEffect(() => () => {
    for (const t of reactionTimers.current) clearTimeout(t);
    reactionTimers.current.clear();
  }, []);

  // Reaktion abfeuern: lokal am eigenen Fenster zeigen + an alle senden
  const fireReaction = (emoji) => {
    const me = room?.localParticipant?.identity || 'me';
    addReactionLocal(emoji, me);
    if (room && room.localParticipant) {
      try {
        const data = new TextEncoder().encode(JSON.stringify({ type: 'emoji', emoji }));
        room.localParticipant.publishData(data, { reliable: true, topic: 'reactions' });
      } catch (e) { console.warn('publishData:', e); }
    }
  };

  const fmt = (s) => `${Math.floor(s/60).toString().padStart(2,'0')}:${(s%60).toString().padStart(2,'0')}`;

  // Tiles ableiten — lokaler Teilnehmer + alle Remotes
  const LK = window.LivekitClient;
  const local = room?.localParticipant;
  const localCamPub = LK && local ? local.getTrackPublication(LK.Track.Source.Camera) : null;
  const localCamTrack = localCamPub && !localCamPub.isMuted ? localCamPub.track : null;
  const remotes = room ? Array.from(room.remoteParticipants.values()) : [];
  const isPaused = pauseUntil > Date.now();

  // Force re-render bei Pause-Ablauf
  React.useEffect(() => {
    if (pauseUntil <= Date.now()) return;
    const t = setTimeout(() => forceRender(), pauseUntil - Date.now() + 50);
    return () => clearTimeout(t);
  }, [pauseUntil]);

  return (
    <div className="call-shell">
      <div className="call-topbar">
        <div className="call-topic">
          <Icon.Sparkle size={28}/>
          {displayedTitle}
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' }}>
          <span className="call-pill live"><span className="dot"></span> Live</span>
          <span className="call-pill"><Icon.Users size={16}/> {1 + remotes.length} {remotes.length === 0 ? 'Person' : 'Personen'}</span>
          <span className="call-pill"><Icon.Clock size={16}/> {fmt(elapsed)}</span>
        </div>
      </div>

      <div className="call-stage">
        <div className="tiles" style={{ position: 'relative' }}>
          {/* Mein Tile */}
          <Tile
            isLocal
            name="Du"
            color="#FFE4B5"
            track={localCamTrack}
            micOn={micOn}
            camError={camError}
            reactions={reactions.filter(r => r.senderId === (local?.identity || 'me'))}
          />

          {/* Remote-Teilnehmer */}
          {remotes.map((p) => {
            const camPub = LK ? p.getTrackPublication(LK.Track.Source.Camera) : null;
            const micPub = LK ? p.getTrackPublication(LK.Track.Source.Microphone) : null;
            const camTrack = camPub && camPub.isSubscribed && !camPub.isMuted ? camPub.track : null;
            const audioTrack = micPub && micPub.isSubscribed && !micPub.isMuted ? micPub.track : null;
            const remoteMicOn = !!micPub && !micPub.isMuted;
            return (
              <Tile
                key={p.identity}
                name={p.name || p.identity}
                color={colorFor(p.identity)}
                track={camTrack}
                audioTrack={audioTrack}
                micOn={remoteMicOn}
                speaking={p.isSpeaking}
                reactions={reactions.filter(r => r.senderId === p.identity)}
              />
            );
          })}

          {/* Verbindungs-Status-Overlay */}
          {conn !== 'connected' && (
            <ConnectionOverlay state={conn} message={connErr}/>
          )}

          {/* Pause-Overlay (alle sehen das, wenn Moderator Pause ansagt) */}
          {isPaused && <PauseOverlay/>}
        </div>

        {/* Seitenleiste */}
        <div className="call-side">
          <div className="side-tabs">
            {!isModerator && (
              <button className={sideTab === 'people' ? 'active' : ''} onClick={() => setSideTab('people')}>
                <Icon.Users size={16}/> Personen
              </button>
            )}
            {isModerator && (
              <>
                <button className={sideTab === 'tools' ? 'active' : ''} onClick={() => setSideTab('tools')}>
                  <Icon.Settings size={16}/> Moderation
                </button>
                <button className={sideTab === 'people' ? 'active' : ''} onClick={() => setSideTab('people')}>
                  <Icon.Users size={16}/> Personen
                </button>
              </>
            )}
          </div>
          <div className="side-body">
            {sideTab === 'people' && (
              <div>
                <div style={{ fontSize: 14, color: 'rgba(255,255,255,0.6)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 12 }}>
                  Wer ist dabei? ({1 + remotes.length})
                </div>
                <PersonRow name="Du" speaking={local?.isSpeaking}/>
                {remotes.map(p => (
                  <PersonRow
                    key={p.identity}
                    name={p.name || p.identity}
                    speaking={p.isSpeaking}
                  />
                ))}
              </div>
            )}
            {sideTab === 'tools' && isModerator && (
              <ModeratorTools room={room} meeting={meeting} onLeave={onLeave}/>
            )}
          </div>
        </div>
      </div>

      {/* Untere Leiste */}
      <div className="call-dock">
        <div className="dock-group">
          <button
            className={"dock-btn icon-only" + (micOn ? '' : ' toggled-off')}
            onClick={() => setMicOn(v => !v)}
            aria-label={micOn ? 'Mikrofon ausschalten' : 'Mikrofon einschalten'}
            title={micOn ? 'Mikrofon ist an' : 'Mikrofon ist aus'}
          >
            <Icon.Mic size={26} off={!micOn}/>
          </button>
          <button
            className={"dock-btn icon-only" + (camOn ? '' : ' toggled-off')}
            onClick={() => setCamOn(v => !v)}
            aria-label={camOn ? 'Kamera ausschalten' : 'Kamera einschalten'}
            title={camOn ? 'Kamera ist an' : 'Kamera ist aus'}
          >
            <Icon.Cam size={26} off={!camOn}/>
          </button>
        </div>

        <div className="emoji-rail huge" role="toolbar" aria-label="Emoji zum Reagieren">
          {EMOJIS.map((e) => (
            <button
              key={e.e}
              className="emoji-btn"
              onClick={() => fireReaction(e.e)}
              aria-label={e.label}
              title={e.label}
            >
              {e.e}
            </button>
          ))}
        </div>

        <div className="dock-group">
          <button className="dock-btn danger" onClick={onLeave}>
            <Icon.Phone size={22}/>
            Verlassen
          </button>
        </div>
      </div>
    </div>
  );
}

// Einzelnes Video-Tile — übernimmt Track-Attach/-Detach selbst
function Tile({ isLocal = false, name, color, track, audioTrack, micOn, speaking, camError, reactions = [] }) {
  const videoRef = React.useRef(null);
  const audioRef = React.useRef(null);

  React.useEffect(() => {
    if (track && videoRef.current) {
      try { track.attach(videoRef.current); } catch (e) { console.warn('video attach:', e); }
      return () => {
        try { track.detach(videoRef.current); } catch { /* ignore */ }
      };
    }
  }, [track]);

  // AudioTrack getrennt attachen — sonst hört man nichts von Remote-Teilnehmern.
  // Für isLocal NICHT attachen, sonst hörst du dich selbst im Echo.
  React.useEffect(() => {
    if (audioTrack && audioRef.current && !isLocal) {
      try { audioTrack.attach(audioRef.current); } catch (e) { console.warn('audio attach:', e); }
      return () => {
        try { audioTrack.detach(audioRef.current); } catch { /* ignore */ }
      };
    }
  }, [audioTrack, isLocal]);

  const cls = "tile" + (isLocal ? ' me' : '') + (speaking ? ' speaking' : '');

  return (
    <div className={cls}>
      {track ? (
        <video ref={videoRef} autoPlay playsInline muted={isLocal}/>
      ) : (
        <>
          <FakeVideo color={color || '#DCE7F8'} name={name}/>
          {camError && isLocal && (
            <div style={{
              position: 'absolute', bottom: 12, right: 12,
              background: 'rgba(220,67,67,0.92)', color: 'white',
              padding: '6px 12px', borderRadius: 'var(--r-full)',
              fontSize: 12, fontWeight: 700,
              display: 'inline-flex', alignItems: 'center', gap: 6,
            }}>
              <Icon.Cam size={14} off/>
              {camError}
            </div>
          )}
        </>
      )}
      {/* Verstecktes Audio-Element nur für Remote-Tiles */}
      {!isLocal && <audio ref={audioRef} autoPlay style={{ display: 'none' }}/>}
      {/* Fliegende Emoji-Reaktionen — diesem Fenster zugeordnet */}
      <div className="tile-reactions">
        {reactions.map(r => (
          <span key={r.id} className="tile-emoji" style={{ left: `${r.offset}%`, '--tilt': `${r.tilt}deg` }}>
            {r.emoji}
          </span>
        ))}
      </div>
      <div className="tile-name">
        {isLocal && <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#16A34A' }}></span>}
        {speaking && !isLocal && <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#FFB547' }}></span>}
        {name}
      </div>
      <div className={"tile-mic" + (micOn ? '' : ' muted')}>
        <Icon.Mic size={18} off={!micOn}/>
      </div>
    </div>
  );
}

function PauseOverlay() {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'rgba(11,20,48,0.85)',
      backdropFilter: 'blur(6px)',
      display: 'grid', placeItems: 'center',
      zIndex: 6,
      borderRadius: 'inherit',
    }}>
      <div style={{
        background: 'var(--cream)', color: 'var(--ink)',
        padding: '32px 40px', borderRadius: 28,
        maxWidth: 460, textAlign: 'center',
        boxShadow: 'var(--shadow-lg)',
      }}>
        <div style={{ fontSize: 48, marginBottom: 12 }}>⏸️</div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 26, marginBottom: 10 }}>
          Wir machen eine kleine Pause
        </div>
        <div className="ls-text" style={{ fontSize: 19 }}>
          <span className="ls-line">Der Moderator hat eine Pause angesagt.</span>
          <span className="ls-line">Gleich geht es weiter.</span>
        </div>
      </div>
    </div>
  );
}

function PersonRow({ name, speaking }) {
  const initials = name.split(' ').map(n => n[0]).join('').slice(0, 2).toUpperCase();
  return (
    <div className="hand-list-item">
      <div style={{ width: 32, height: 32, borderRadius: '50%', background: 'rgba(255,255,255,0.14)', display: 'grid', placeItems: 'center', fontSize: 14, fontWeight: 700 }}>
        {initials}
      </div>
      <div className="nm">{name}</div>
      {speaking && <span style={{ background: '#FFB547', color: 'var(--ink)', fontSize: 11, padding: '2px 8px', borderRadius: 8, fontWeight: 700 }}>spricht</span>}
    </div>
  );
}

function ConnectionOverlay({ state, message }) {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'rgba(11, 20, 48, 0.85)',
      backdropFilter: 'blur(6px)',
      display: 'grid', placeItems: 'center',
      zIndex: 5,
      borderRadius: 'inherit',
    }}>
      <div style={{
        background: 'var(--paper)', color: 'var(--ink)',
        padding: '28px 36px', borderRadius: 'var(--r-md)',
        maxWidth: 420, textAlign: 'center',
        boxShadow: 'var(--shadow-lg)',
      }}>
        {state === 'ended' ? (
          <>
            <div style={{ fontSize: 36, marginBottom: 10 }}>👋</div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, marginBottom: 8 }}>
              Das Treffen ist zu Ende
            </div>
            <div className="ls-text" style={{ fontSize: 17 }}>
              <span className="ls-line">Danke, dass du dabei warst.</span>
              <span className="ls-line">Wir bringen dich zurück zur Start-Seite.</span>
            </div>
          </>
        ) : state === 'error' ? (
          <>
            <div style={{ fontSize: 36, marginBottom: 10 }}>⚠️</div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, marginBottom: 8 }}>
              Verbindung fehlgeschlagen
            </div>
            <div className="ls-text" style={{ fontSize: 17 }}>
              <span className="ls-line">Wir konnten dich nicht verbinden.</span>
              <span className="ls-line">Bitte probiere es später noch einmal.</span>
            </div>
            {message && (
              <div className="muted" style={{ fontSize: 13, marginTop: 12 }}>
                {message}
              </div>
            )}
          </>
        ) : (
          <>
            <div style={{ fontSize: 36, marginBottom: 10 }}>⏳</div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, marginBottom: 8 }}>
              Verbinde dich gerade...
            </div>
            <div className="ls-text" style={{ fontSize: 17 }}>
              <span className="ls-line">Einen kleinen Moment bitte.</span>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

// "Gefälschtes" Video-Tile — Pastell-Hintergrund + sympathisches Gesicht
// für Teilnehmer ohne Kamera-Stream
function FakeVideo({ color, name }) {
  const initials = name.split(' ').map(n => n[0]).slice(0, 2).join('').toUpperCase();
  return (
    <svg viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%' }}>
      <defs>
        <radialGradient id={`g-${initials}`} cx="50%" cy="40%" r="70%">
          <stop offset="0%" stopColor={color} stopOpacity="1"/>
          <stop offset="100%" stopColor={color} stopOpacity="0.5"/>
        </radialGradient>
      </defs>
      <rect width="400" height="300" fill={`url(#g-${initials})`}/>
      <ellipse cx="200" cy="320" rx="120" ry="100" fill="rgba(20,46,115,0.15)"/>
      <circle cx="200" cy="160" r="60" fill="rgba(20,46,115,0.18)"/>
      <circle cx="183" cy="155" r="4" fill="rgba(20,46,115,0.5)"/>
      <circle cx="217" cy="155" r="4" fill="rgba(20,46,115,0.5)"/>
      <path d="M183 178c5 5 29 5 34 0" stroke="rgba(20,46,115,0.5)" strokeWidth="3" fill="none" strokeLinecap="round"/>
    </svg>
  );
}

function ModeratorTools({ room, meeting, onLeave }) {
  const [busy, setBusy] = React.useState(null);
  const [feedback, setFeedback] = React.useState(null);
  const [dialog, setDialog] = React.useState(null);

  const flash = (msg) => {
    setFeedback(msg);
    setTimeout(() => setFeedback(null), 2500);
  };

  const muteAll = () => {
    if (busy || !meeting) return;
    setDialog({
      type: 'confirm',
      message: 'Alle Teilnehmer wirklich stumm-schalten?',
      onConfirm: async () => {
        setDialog(null);
        setBusy('mute');
        try {
          const r = await window.Api.muteAll(meeting.id);
          flash(`${r.mutedCount} Teilnehmer stumm-geschaltet`);
        } catch (e) {
          if (window.showToast) window.showToast('Das Stumm-Schalten hat nicht geklappt.', 'error');
          flash('Das hat leider nicht geklappt.');
        }
        setBusy(null);
      },
      onCancel: () => setDialog(null),
    });
  };

  const changeTopic = () => {
    if (busy || !meeting) return;
    setDialog({
      type: 'prompt',
      message: 'Neues Thema:',
      defaultValue: meeting.title,
      onSubmit: async (t) => {
        setDialog(null);
        if (!t || t === meeting.title) return;
        setBusy('topic');
        try {
          await window.Api.changeTopic(meeting.id, t);
          flash('Thema geändert');
        } catch (e) {
          if (window.showToast) window.showToast('Das Thema konnte nicht geändert werden.', 'error');
          flash('Das hat leider nicht geklappt.');
        }
        setBusy(null);
      },
      onCancel: () => setDialog(null),
    });
  };

  const pause = async () => {
    if (busy || !room) return;
    setBusy('pause');
    try {
      const data = new TextEncoder().encode(JSON.stringify({ type: 'pause' }));
      await room.localParticipant.publishData(data, { reliable: true, topic: 'pause' });
      flash('Pause-Signal gesendet');
    } catch (e) {
      if (window.showToast) window.showToast('Das Pause-Signal konnte nicht gesendet werden.', 'error');
      flash('Das hat leider nicht geklappt.');
    }
    setBusy(null);
  };

  const endMeeting = () => {
    if (busy || !meeting) return;
    setDialog({
      type: 'confirm',
      message: 'Treffen für alle beenden? Niemand kann mehr beitreten.',
      onConfirm: async () => {
        setDialog(null);
        setBusy('end');
        try {
          await window.Api.endMeeting(meeting.id);
        } catch { /* trotzdem verlassen */ }
        setBusy(null);
        onLeave?.();
      },
      onCancel: () => setDialog(null),
    });
  };

  const tools = [
    { icon: '🎤', label: 'Alle stumm-schalten', onClick: muteAll, key: 'mute' },
    { icon: '📋', label: 'Thema ändern', onClick: changeTopic, key: 'topic' },
    { icon: '⏸️', label: 'Pause einlegen', onClick: pause, key: 'pause' },
    { icon: '⏹️', label: 'Treffen beenden', onClick: endMeeting, key: 'end', danger: true },
  ];
  return (
    <div>
      <div style={{ fontSize: 14, color: 'rgba(255,255,255,0.6)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 12 }}>
        Moderations-Werkzeuge
      </div>
      {tools.map(t => (
        <button
          key={t.key}
          className="mod-action"
          onClick={t.onClick}
          disabled={busy !== null}
          style={t.danger ? { background: 'rgba(220,67,67,0.18)' } : {}}
        >
          <span className="ico" style={{ fontSize: 18, ...(t.danger ? { background: 'rgba(220,67,67,0.25)', color: '#FF8888' } : {}) }}>{t.icon}</span>
          {busy === t.key ? 'Wird ausgeführt...' : t.label}
        </button>
      ))}
      {feedback && (
        <div style={{
          marginTop: 12, padding: '10px 14px', borderRadius: 12,
          background: 'rgba(22,163,74,0.18)', color: '#86EFAC',
          fontSize: 14, fontWeight: 700,
        }}>
          {feedback}
        </div>
      )}

      {dialog && dialog.type === 'confirm' && (
        <ConfirmDialog
          message={dialog.message}
          onConfirm={dialog.onConfirm}
          onCancel={dialog.onCancel}
        />
      )}
      {dialog && dialog.type === 'prompt' && (
        <PromptDialog
          message={dialog.message}
          defaultValue={dialog.defaultValue}
          onSubmit={dialog.onSubmit}
          onCancel={dialog.onCancel}
        />
      )}
    </div>
  );
}

Object.assign(window, { VideoCall });
