using System.Collections.Concurrent;
using Microsoft.AspNetCore.SignalR;

namespace PongGame.Hubs;

public class PongLobby {
    private readonly HashSet<PongPlayer> connectedPlayers = new();
    private readonly Dictionary<string, PongRoom> PongRooms = new();

    public PongLobby(ILogger<PongLobby> logger)
        => Logger = logger;

    public const int ROOM_ID_LENGTH = 4;

    public PongPlayer CreatePlayer() {
        var player = new PongPlayer();
        lock (connectedPlayers)
            connectedPlayers.Add(player);
        return player;
    }

    public void RemovePlayer(PongPlayer player) {
        if (player.ConnectedRoom is PongRoom room)
            room.Leave(player);
        lock (connectedPlayers)
            _ = connectedPlayers.Remove(player);
    }

    public PongRoom CreateRoom(PongPlayer player) {
        PongRoom room;
        lock (PongRooms) {
            room = new(GenerateRoomId(), Logger);
            PongRooms.Add(room.ID, room);
        }
        room.Join(player);
        return room;
    }

    public PongRoom JoinRoom(PongPlayer player, string roomId) {
        PongRoom? room;
        lock (PongRooms) {
            room = PongRooms.GetValueOrDefault(roomId);
        }
        if (room is null) throw new HubException($"Room [{roomId}] not found!");
        room.Join(player);
        return room;
    }

    public void LeaveRoom(PongPlayer player) {
        if (player.ConnectedRoom is PongRoom room)
            room.Leave(player);
    }

    private readonly Random random = new();
    private readonly ILogger<PongLobby> Logger;
    private const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private string GenerateRoomId() {
        string id;
        do {
            id = string.Concat(Enumerable.Range(0, ROOM_ID_LENGTH).Select(_ => ALPHABET[random.Next(ALPHABET.Length)]));
        } while (PongRooms.ContainsKey(id));
        return id;
    }
}