// In-memory lobby snapshot, the lobby counterpart of gamecache.ts. The lobby re-fetches
// its lists on every entry, so without a cache the screen renders blank and "draws in"
// during the back-slide from a game. Caching the last lists lets the lobby render
// instantly (before/under the transition) and refresh in the background. Process-memory
// only; cleared on logout.

import type { AccountRef, GameView, Invitation } from './model';

interface LobbySnapshot {
  games: GameView[];
  invitations: Invitation[];
  incoming: AccountRef[];
}

let snapshot: LobbySnapshot | null = null;

/** getLobby returns the last lobby lists, or null before the first load. The unified lobby caches one
 *  snapshot (device-local + server games merged); offline reuses its server games, greyed, and drops
 *  the local ones for a fresh device read. */
export function getLobby(): LobbySnapshot | null {
  return snapshot;
}

/** setLobby stores the latest lobby lists. */
export function setLobby(s: LobbySnapshot): void {
  snapshot = s;
}

/**
 * patchLobbyGame upserts the given game into the cached lobby — replacing the matching entry, or
 * prepending it when absent — so a game-state change seen while the lobby is unmounted (the player's
 * own move, or any live game event the global stream handler applies from another screen) is already
 * reflected the next time the lobby renders from the snapshot, instead of showing the stale status
 * until the background refresh lands. Prepending a freshly started game likewise lets it appear at
 * once. It is a no-op only when there is no snapshot yet (the lobby cold-loads on its first mount).
 * The lobby re-groups and re-sorts on render, so the insert position carries no meaning.
 */
export function patchLobbyGame(g: GameView): void {
  if (!snapshot) return;
  const i = snapshot.games.findIndex((x) => x.id === g.id);
  const games = snapshot.games.slice();
  if (i === -1) games.unshift(g);
  else games[i] = g;
  snapshot = { ...snapshot, games };
}

/**
 * patchLobbyInvitation applies a live invitation change to the cached lobby's invitations list, so a
 * change seen while the lobby is unmounted is reflected on its next render instead of a stale card
 * lingering until the background refresh. A still-pending invitation is upserted (a new one
 * prepended newest-first, an updated one replaced in place); an invitation that reached any terminal
 * status (started, declined, cancelled, expired) is removed — the authoritative list holds only
 * pending invitations. It is a no-op when there is no snapshot yet, or a terminal invitation is not
 * in the list. The lobby re-renders from the snapshot, so the in-place upsert needs no re-sort.
 */
export function patchLobbyInvitation(inv: Invitation): void {
  if (!snapshot) return;
  const i = snapshot.invitations.findIndex((x) => x.id === inv.id);
  let invitations: Invitation[];
  if (inv.status !== 'pending') {
    if (i === -1) return; // a terminal invitation already absent — nothing to remove
    invitations = snapshot.invitations.filter((x) => x.id !== inv.id);
  } else if (i === -1) {
    invitations = [inv, ...snapshot.invitations];
  } else {
    invitations = snapshot.invitations.slice();
    invitations[i] = inv;
  }
  snapshot = { ...snapshot, invitations };
}

/** clearLobby drops the cached lobby (called on logout). */
export function clearLobby(): void {
  snapshot = null;
}
