/**
 * Reusable Room/Session helper functions
 * These are application-agnostic and work with any Room/Session implementation
 */

import type { BaseSession, Participant, Session, Room } from './types';

/**
 * Get participant list for a room
 * Returns minimal session information suitable for client-side participant lists
 */
export function getParticipants<TMetadata = any>(
  sessions: Record<string, Session<TMetadata>>
): Participant[] {
  const participants: Participant[] = [];

  for (const id in sessions) {
    const session = sessions[id];
    if (!session) continue;

    participants.push({
      name: session.name,
      session_id: session.id,
      live: session.live,
      protected: session.protected || false,
      has_media: session.has_media,
      bot_run_id: session.bot_run_id || null,
      bot_provider_id: session.bot_provider_id || null,
      bot_instance_id: session.bot_instance_id || null,
      muted: false, // TODO: Track mute state separately
      video_on: true, // TODO: Track video state separately
    });
  }

  return participants;
}

/**
 * Get a session by ID
 */
export function getSession<TMetadata = any>(
  sessions: Record<string, Session<TMetadata>>,
  sessionId: string
): Session<TMetadata> | undefined {
  return sessions[sessionId];
}

/**
 * Create a new base session
 */
export function createBaseSession(sessionId: string, name: string | null = null): BaseSession {
  return {
    id: sessionId,
    name,
    live: false,
    connected: false,
    lastActive: Date.now(),
    has_media: true, // Default to true
    _initialSnapshotSent: false,
  };
}

/**
 * Update session activity timestamp
 */
export function updateSessionActivity<TMetadata = any>(
  session: Session<TMetadata>
): void {
  session.lastActive = Date.now();
  session.live = true;
}

/**
 * Check if a session is active
 */
export function isSessionActive<TMetadata = any>(
  session: Session<TMetadata>,
  timeoutMs: number = 60000
): boolean {
  if (!session.live) return false;
  return Date.now() - session.lastActive < timeoutMs;
}

/**
 * Get the display name for a session
 */
export function getSessionName<TMetadata = any>(
  session: Session<TMetadata> | undefined
): string {
  if (!session) return 'Unknown';
  return session.name || session.id;
}

/**
 * Filter active sessions
 */
export function getActiveSessions<TMetadata = any>(
  sessions: Record<string, Session<TMetadata>>
): Session<TMetadata>[] {
  return Object.values(sessions).filter(s => s && isSessionActive(s));
}

/**
 * Count active sessions
 */
export function countActiveSessions<TMetadata = any>(
  sessions: Record<string, Session<TMetadata>>
): number {
  return getActiveSessions(sessions).length;
}

/**
 * Remove inactive sessions
 */
export function cleanupInactiveSessions<TMetadata = any>(
  sessions: Record<string, Session<TMetadata>>,
  timeoutMs: number = 300000 // 5 minutes
): void {
  for (const id in sessions) {
    const session = sessions[id];
    if (session && !isSessionActive(session, timeoutMs)) {
      delete sessions[id];
    }
  }
}

// ============================================================================
// Metadata Helper Functions
// ============================================================================

/**
 * Get session metadata safely with type checking
 * @param session - The session to get metadata from
 * @returns The metadata object or undefined
 */
export function getSessionMetadata<TMetadata = any>(
  session: Session<TMetadata>
): TMetadata | undefined {
  return session.metadata;
}

/**
 * Update session metadata (creates metadata object if it doesn't exist)
 * @param session - The session to update
 * @param updates - Partial metadata updates to apply
 */
export function updateSessionMetadata<TMetadata = any>(
  session: Session<TMetadata>,
  updates: Partial<TMetadata>
): void {
  if (!session.metadata) {
    session.metadata = {} as TMetadata;
  }
  Object.assign(session.metadata as any, updates);
}

/**
 * Get room metadata safely with type checking
 * @param room - The room to get metadata from
 * @returns The metadata object or undefined
 */
export function getRoomMetadata<TMetadata = any>(
  room: Room<TMetadata>
): TMetadata | undefined {
  return room.metadata;
}

/**
 * Update room metadata (creates metadata object if it doesn't exist)
 * @param room - The room to update
 * @param updates - Partial metadata updates to apply
 */
export function updateRoomMetadata<TMetadata = any>(
  room: Room<TMetadata>,
  updates: Partial<TMetadata>
): void {
  if (!room.metadata) {
    room.metadata = {} as TMetadata;
  }
  Object.assign(room.metadata as any, updates);
}

/**
 * Check if session has metadata
 */
export function hasSessionMetadata<TMetadata = any>(
  session: Session<TMetadata>
): boolean {
  return session.metadata !== undefined && session.metadata !== null;
}

/**
 * Check if room has metadata
 */
export function hasRoomMetadata<TMetadata = any>(
  room: Room<TMetadata>
): boolean {
  return room.metadata !== undefined && room.metadata !== null;
}
