'use client';

import { useCallback, useEffect, useState } from 'react';
import type { HostState } from '@pintrush/engine';
import type { GameConnection, GameViewState } from '@/lib/game';

interface HostSyncData {
  eventId: string | null;
  seq: number;
  host: HostState | null;
}

/**
 * The freshest HostState for one event.
 *
 * Transition envelopes carry `host` and the connection stores it, but `room.state` envelopes (the
 * throttled join/answer-count updates and the snapshot after a session switch) arrive with a full
 * snapshot whose `host` the shared connection does not keep. So after every room.state, and when
 * asked, we pull the roster with the read-only `host.sync` ack and use whichever copy is newer by
 * session seq. Views for another session (the server shows the room's active session to host
 * sockets until this event is opened) are ignored.
 */
export function useHostView(conn: GameConnection | null, state: GameViewState, eventId: string) {
  const envHost = state.host && state.host.public.eventId === eventId ? state.host : null;
  const [envSeq, setEnvSeq] = useState(-1);
  const [synced, setSynced] = useState<{ host: HostState | null; seq: number } | null>(null);

  // Remember the seq at which the envelope copy last changed.
  useEffect(() => {
    if (envHost) setEnvSeq(state.seq);
    // state.seq is read at the moment envHost changes; it must not re-run on every seq bump.
  }, [envHost]);

  const sync = useCallback(async () => {
    if (!conn) return;
    const res = await conn.emit<HostSyncData>('host.sync', { eventId });
    if (res.ok && res.data && (res.data.eventId === eventId || res.data.host === null)) {
      const host = res.data.host && res.data.host.public.eventId === eventId ? res.data.host : null;
      setSynced({ host, seq: res.data.seq });
    }
  }, [conn, eventId]);

  const connected = state.status === 'connected';
  const isRoomState = state.lastType === 'room.state';
  useEffect(() => {
    if (connected && isRoomState) void sync();
  }, [connected, isRoomState, state.messageCount, sync]);

  const host = synced && synced.seq > envSeq ? synced.host : (envHost ?? synced?.host ?? null);
  return { host, sync };
}
