import { randomUUID } from 'node:crypto'

export type LiveChatMessage = {
  id: string
  username: string
  text: string
  createdAt: number
}

type LiveChatRoom = {
  messages: LiveChatMessage[]
  sockets: Set<string>
}

const MAX_MESSAGES_PER_ROOM = 100

export class LiveChatStore {
  private readonly rooms = new Map<string, LiveChatRoom>()

  joinRoom (streamKey: string, socketId: string) {
    const room = this.getOrCreateRoom(streamKey)

    room.sockets.add(socketId)

    return room
  }

  leaveRoom (streamKey: string, socketId: string) {
    const room = this.rooms.get(streamKey)
    if (!room) return

    room.sockets.delete(socketId)

    if (room.sockets.size === 0 && room.messages.length === 0) {
      this.rooms.delete(streamKey)
    }
  }

  addMessage (streamKey: string, username: string, text: string) {
    const room = this.getOrCreateRoom(streamKey)
    const message: LiveChatMessage = {
      id: randomUUID(),
      username,
      text,
      createdAt: Date.now()
    }

    room.messages.push(message)
    if (room.messages.length > MAX_MESSAGES_PER_ROOM) {
      room.messages.splice(0, room.messages.length - MAX_MESSAGES_PER_ROOM)
    }

    return message
  }

  getRecentMessages (streamKey: string) {
    return [ ...(this.rooms.get(streamKey)?.messages || []) ]
  }

  getPresenceCount (streamKey: string) {
    return this.rooms.get(streamKey)?.sockets.size || 0
  }

  deleteRoom (streamKey: string) {
    return this.rooms.delete(streamKey)
  }

  private getOrCreateRoom (streamKey: string) {
    let room = this.rooms.get(streamKey)

    if (!room) {
      room = {
        messages: [],
        sockets: new Set<string>()
      }

      this.rooms.set(streamKey, room)
    }

    return room
  }
}
