// server/routes/games/sessionState.ts

import {
  TransientGameState,
  TransientSessionState,
  TRANSIENT_SESSION_KEYS,
  TRANSIENT_GAME_KEYS
} from "./transientSchema";
import { Game, Session } from "./types";

class TransientStateManager {
  private sessions = new Map<string, TransientSessionState>();
  private games = new Map<string, TransientGameState>();

  // Session transient state
  preserveSession(gameId: string, sessionId: string, session: Session): void {
    const key = `${gameId}:${sessionId}`;
    const transient: any = {};

    // Automatically preserve all transient fields from schema
    TRANSIENT_SESSION_KEYS.forEach((k) => {
      if (k in session) {
        transient[k] = session[k];
      }
    });

    this.sessions.set(key, transient);
  }

  restoreSession(gameId: string, sessionId: string, session: Session): void {
    const key = `${gameId}:${sessionId}`;
    const transient = this.sessions.get(key);
    if (transient) {
      Object.assign(session, transient);
      // Don't delete - keep for future loads
    }
  }

  clearSession(gameId: string, sessionId: string): void {
    const key = `${gameId}:${sessionId}`;
    const transient = this.sessions.get(key);
    if (transient) {
      // Clean up timers
      if (transient.keepAlive) clearTimeout(transient.keepAlive);
      if (transient.pingInterval) clearTimeout(transient.pingInterval);
      if (transient._getBatch?.timer) clearTimeout(transient._getBatch.timer);
      if (transient._pendingTimeout) clearTimeout(transient._pendingTimeout);
    }
    this.sessions.delete(key);
  }

  // Game transient state
  preserveGame(gameId: string, game: Game): void {
    const transient: any = {};

    // Automatically preserve all transient fields from schema
    TRANSIENT_GAME_KEYS.forEach((k) => {
      if (k in game) {
        transient[k] = game[k];
      }
    });

    this.games.set(gameId, transient);
  }

  restoreGame(gameId: string, game: Game): void {
    const transient = this.games.get(gameId);
    if (transient) {
      Object.assign(game, transient);
    }
  }

  clearGame(gameId: string): void {
    const transient = this.games.get(gameId);
    if (transient?.turnTimer) {
      clearTimeout(transient.turnTimer);
    }
    this.games.delete(gameId);
  }

  /**
   * Remove all transient fields from a session object (for serialization)
   * Automatically uses all keys from TRANSIENT_SESSION_SCHEMA
   */
  stripSessionTransients(session: any): void {
    // Remove all transient fields automatically
    TRANSIENT_SESSION_KEYS.forEach((key) => delete session[key]);

    // Remove player reference (runtime only)
    delete session.player;

    // Catch-all: remove any underscore-prefixed fields and functions
    Object.keys(session).forEach((k) => {
      if (k.startsWith("_")) delete session[k];
      else if (typeof session[k] === "function") delete session[k];
    });
  }

  /**
   * Remove all transient fields from a game object (for serialization)
   * Automatically uses all keys from TRANSIENT_GAME_SCHEMA
   */
  stripGameTransients(game: any): void {
    TRANSIENT_GAME_KEYS.forEach((key) => delete game[key]);
  }
}

export const transientState = new TransientStateManager();