import type { WebSocket } from '@fastify/websocket';

/**
 * Session information for an active user connection.
 */
export interface Session {
  userId: string;
  sessionId: string;
  socket: WebSocket;
  channelType: 'websocket' | 'telegram';
  containerEndpoint: string; // Container's XPUB endpoint for informational events
  connectedAt: Date;
}

/**
 * Registry of active user sessions.
 * Used by event system to route events to connected users.
 */
export class SessionRegistry {
  // Map of userId -> Session (only most recent session per user)
  private sessions = new Map<string, Session>();

  // Map of sessionId -> userId (for reverse lookup)
  private sessionToUser = new Map<string, string>();

  /**
   * Register a new session for a user.
   * If user already has a session, the old one is replaced.
   */
  register(session: Session): void {
    // Remove old session if exists
    const oldSession = this.sessions.get(session.userId);
    if (oldSession) {
      this.sessionToUser.delete(oldSession.sessionId);
    }

    this.sessions.set(session.userId, session);
    this.sessionToUser.set(session.sessionId, session.userId);
  }

  /**
   * Unregister a session.
   */
  unregister(sessionId: string): Session | undefined {
    const userId = this.sessionToUser.get(sessionId);
    if (!userId) return undefined;

    const session = this.sessions.get(userId);
    if (session && session.sessionId === sessionId) {
      this.sessions.delete(userId);
      this.sessionToUser.delete(sessionId);
      return session;
    }

    return undefined;
  }

  /**
   * Get session by user ID.
   */
  get(userId: string): Session | undefined {
    return this.sessions.get(userId);
  }

  /**
   * Get session by session ID.
   */
  getBySessionId(sessionId: string): Session | undefined {
    const userId = this.sessionToUser.get(sessionId);
    if (!userId) return undefined;
    return this.sessions.get(userId);
  }

  /**
   * Check if user has an active session.
   */
  has(userId: string): boolean {
    return this.sessions.has(userId);
  }

  /**
   * Get all active sessions.
   */
  all(): Session[] {
    return Array.from(this.sessions.values());
  }

  /**
   * Get count of active sessions.
   */
  size(): number {
    return this.sessions.size;
  }

  /**
   * Get all user IDs with active sessions.
   */
  userIds(): string[] {
    return Array.from(this.sessions.keys());
  }

  /**
   * Send a message to a user's active session.
   * Returns true if message was sent, false if no active session.
   */
  sendToUser(userId: string, message: string | Buffer): boolean {
    const session = this.sessions.get(userId);
    if (!session) return false;

    try {
      session.socket.send(message);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Broadcast a message to all active sessions.
   * Returns number of sessions that received the message.
   */
  broadcast(message: string | Buffer): number {
    let sent = 0;
    for (const session of this.sessions.values()) {
      try {
        session.socket.send(message);
        sent++;
      } catch {
        // Session may have disconnected
      }
    }
    return sent;
  }
}
