using Microsoft.AspNetCore.SignalR;

namespace PongGame.Hubs;

public class PongHub : Hub<IPongClient> {
    private const string PLAYER_KEY = "PLAYER";
    private readonly PongLobby Lobby;
    private readonly ILogger<PongHub> Logger;

    public PongHub(PongLobby lobby, ILogger<PongHub> logger) : base() {
        Lobby = lobby;
        Logger = logger;
    }

    private PongPlayer Player {
        get => (Context.Items.TryGetValue(PLAYER_KEY, out var player) ? player as PongPlayer : null)
            ?? throw new InvalidProgramException("Player was not assigned at connection start!");
        set => Context.Items[PLAYER_KEY] = value;
    }

    public override Task OnConnectedAsync() {
        Player = Lobby.CreatePlayer();
        Player.Client = Clients.Client(Context.ConnectionId);
        Player.Username = "Anon";
        return Task.CompletedTask;
    }

    private void AssertNotInRoom() {
        if (Player.ConnectedRoom is PongRoom currentRoom)
            throw new HubException($"User is already connected to room [{currentRoom}]");
    }

    public Task<string> CreateRoom() {
        AssertNotInRoom();
        var room = Lobby.CreateRoom(Player);
        return Task.FromResult(room.ID);
    }

    public Task<string> JoinRoom(string roomId) {
        AssertNotInRoom();
        var room = Lobby.JoinRoom(Player, roomId);
        return Task.FromResult(room.ID);
    }

    public Task LeaveRoom() {
        Lobby.LeaveRoom(Player);
        return Task.CompletedTask;
    }

    public Task RequestUsernameChange(string username) {
        // TOOD: check this
        Logger.LogInformation($"Player {Player} requested username change to [{username}]");
        Player.Username = username;
        return Task.CompletedTask;
    }

    public override Task OnDisconnectedAsync(Exception? exception) {
        Lobby.RemovePlayer(Player);
        return Task.CompletedTask;
    }
}
