#pragma once

/**
 * \file Game.h
 * \brief File containing the blitz::game::Game class
 */

#include "Player.h"
#include "blitz/misc/Time.h"
#include <map>

namespace blitz {
namespace game {

/**
 * \typedef PlayerMap
 * \brief A map of players
 */
typedef std::map<PlayerID, Player> PlayerMap;

/**
 * \enum GameState
 * \brief The states of the game
 */
enum GameState : std::uint8_t {
	gsNone = 0,	 /**< Default state */
	gsWaiting,	 /**< Waiting state if the number of players is less than 2 */
	gsPreparing, /**< Preparing state until the game start */
	gsGame,		 /**< Game state during the players can shoot and kill ... */
	gsEnd,		 /**< End state of the game : show the winner of the game and the leaderboard*/
};

/**
 * \brief The game configuration
 * \struct GameConfig
 */
struct GameConfig {
	/**
	 * \brief The gravity applied to players
	 */
	float Gravity;
	/**
	 * \brief The firing rate of the shoot in RPM (round per minute)
	 */
	int FiringRate;
};

/**
 * \class Game
 * \brief Class representing a game
 */
class Game {
  protected:
	PlayerMap m_Players;
	GameState m_GameState;
	utils::Timer m_GameTimer;
	GameConfig m_Config;

  public:
	/** \brief Default constructor */
	Game() : m_GameState(gsNone) {}

	/**
	 * \brief Update the game with a delta time
	 * \param delta The time elapsed since the last update in milliseconds
	 */
	virtual void Tick(std::uint64_t delta) = 0;

	/**
	 * \brief Get a player by its identifier
	 * \param id The identifier of the player
	 * \return The player if found, nullptr otherwise
	 */
	Player* GetPlayerById(PlayerID id);

	/**
	 * \brief Get a player by its identifier (const version)
	 * \param id The identifier of the player
	 * \return The player if found, nullptr otherwise
	 */
	const Player* GetPlayerById(PlayerID id) const;

	/**
	 * \brief Get the players
	 * \return The map of players
	 */
	PlayerMap& GetPlayers() {
		return m_Players;
	}

	/**
	 * \brief Get the players (const version)
	 * \return The map of players
	 */
	const PlayerMap& GetPlayers() const {
		return m_Players;
	}

	/**
	 * \brief Get the game state
	 * \return The game state
	 */
	GameState GetGameState() const {
		return m_GameState;
	}

	/**
	 * \brief Load the game configuration
	 * \param config The game configuration to load
	 */
	void LoadConfig(const GameConfig& config) {
		m_Config = config;
	}

	/**
	 * \brief Get the game configuration
	 * \return The game configuration
	 */
	const game::GameConfig& GetGameConfig() const {
		return m_Config;
	}

	/**
	 * \brief Add a player to the game
	 * \param player The identifier of the player
	 * \param name The name of the player
	 */
	virtual void AddPlayer(PlayerID player, const std::string& name);
	/**
	 * \brief Remove a player from the game
	 * \param player The identifier of the player
	 */
	virtual void RemovePlayer(PlayerID player);

	/**
	 * \brief Get the remaining time of the game
	 * \return The remaining time of the game in milliseconds
	 */
	std::uint64_t GetGameStateRemainingTime() const {
		return m_GameTimer.GetTimeRemaining();
	}
};


}  // namespace game
}  // namespace blitz
