using Microsoft.AspNetCore.SignalR;

namespace PongGame.Hubs;

public class PongRoom {
    public string ID { get; }
    private readonly ILogger Logger;

    public PongRoom(string id, ILogger logger) {
        ID = id;
        Logger = logger;
    }

    public PongPlayer? Player1 { get; private set; }
    public PongPlayer? Player2 { get; private set; }
    public GameState State { get; private set; } = GameState.WaitingForPlayers;

    public void Join(PongPlayer player) {
        // TODO: synchronize this
        if (Player1 is null) {
            Player1 = player;
            Logger.LogInformation($"[{ID}] {player} joined pong room as player 1!");
        } else if (Player2 is null) {
            Player2 = player;
            Logger.LogInformation($"[{ID}] {player} joined pong room as player 2!");
        } else
            throw new HubException($"Lobby [{ID}] is already full!");
        _ = Task.Run(PlayersChanged);
        player.ConnectedRoom = this;
    }

    public void Leave(PongPlayer player) {
        if (Player1 == player) {
            Player1 = null;
            Logger.LogInformation($"[{ID}] Player 1 {player} left pong room!");
        } else if (Player2 == player) {
            Player2 = null;
            Logger.LogInformation($"[{ID}] Player 2 {player} left pong room!");
        }
        player.ConnectedRoom = null;
        _ = Task.Run(PlayersChanged);
    }

    private Task PlayersChanged() {
        if (Player1 is PongPlayer player1 && Player2 is PongPlayer player2) {
            ResumeGame(player1, player2);
        } else if (Player1 is null && Player2 is null) {
            CloseRoom();
        } else
            PauseGame();
        return Task.CompletedTask;
    }

    private void ResumeGame(PongPlayer player1, PongPlayer player2) {
        Logger.LogInformation($"[{ID}] Pong game started: {player1} vs. {player2}");
        State = GameState.InProgress;
        player1.Client.GameStateChanged(State);
        player2.Client.GameStateChanged(State);
    }

    private void PauseGame() => State = GameState.WaitingForPlayers;
    private void CloseRoom() => State = GameState.Finished;

    public override string ToString() => $"[{ID}]";
}