#pragma once

#if defined(WITH_MULTIPLAYER) || defined(DOXYGEN_GENERATING_OUTPUT)

#include "Peer.h"
#include "../PlayerType.h"
#include "../PreferencesCache.h"
#include "../../nCine/Base/TimeStamp.h"

#include <Containers/String.h>

using namespace Death::Containers;
using namespace nCine;

namespace Jazz2::Actors::Multiplayer
{
	class MpPlayer;
}

namespace Jazz2::Multiplayer
{
	/** @brief Peer state in a level  */
	enum class PeerLevelState
	{
		Unknown,				/**< Unknown */
		ValidatingAssets,		/**< Peer received list of required assets, the server is waiting for response */
		StreamingMissingAssets,	/**< Missing assets are being streamed to peer */
		LevelLoaded,			/**< Peer finished loading of the level */
		LevelSynchronized,		/**< Peer finished synchronized entities in the level */
		Spectating,				/**< Peer is spectating */
		PlayerReady,			/**< Player is ready to spawn */
		PlayerSpawned			/**< Player is spawned */
	};

	/** @brief Spectate mode flags */
	enum class SpectateMode : std::uint8_t {
		None,					/**< Not spectating */
		Forced,					/**< Spectate mode is forced by the server, the client cannot disable it */
		Requested,				/**< Spectate mode is requested by the client, the server can accept or reject it */

		FreeCamera = 0x10,		/**< Spectate with free camera, otherwise spectate with player camera */

		Mask = 0x0F				/**< Mask for spectate mode flags */
	};

	DEATH_ENUM_FLAGS(SpectateMode);

	/** @brief Peer descriptor */
	struct PeerDescriptor
	{
		/** @brief Remote peer if the peer is connected remotely */
		Peer RemotePeer;

		/** @brief Unique Player ID if the peer is connected remotely */
		Uuid UniquePlayerID;
		/** @brief Whether the peer is already successfully authenticated */
		bool IsAuthenticated;
		/** @brief Whether the peer has admin privileges */
		bool IsAdmin;
		/** @brief Whether ledge climbing is enabled by client */
		bool EnableLedgeClimb;
		/** @brief Whether the peer voted "yes" in the active poll */
		bool VotedYes;
		/** @brief Team ID */
		std::uint8_t Team;
		/** @brief Preferred player type selected by the peer */
		PlayerType PreferredPlayerType;
		/** @brief Player display name */
		String PlayerName;
		/** @brief Earned points in the current session (championship) */
		std::uint32_t Points;
		/** @brief Game mode specific points held by the player in a round */
		std::uint32_t PointsInRound;
		/** @brief Position in a round */
		std::uint32_t PositionInRound;
		/** @brief State of the player in the current level */
		PeerLevelState LevelState;
		/** @brief Spawned player in the current level */
		Actors::Multiplayer::MpPlayer* Player;
		/** @brief Last update of the player from client */
		std::uint64_t LastUpdated;

		/** @brief Deaths of the player in the current round */
		std::uint32_t Deaths;
		/** @brief Kills of the player in the current round */
		std::uint32_t Kills;
		/** @brief Laps of the player in the current round */
		std::uint32_t Laps;
		/** @brief Timestamp when the last lap started */
		TimeStamp LapStarted;
		/** @brief Treasure collected of the player in the current round */
		std::uint32_t TreasureCollected;

		/** @brief Elapsed frames when the player is idle */
		float IdleElapsedFrames;
		/** @brief Elapsed frames when the player lost all lives */
		float DeathElapsedFrames;
		/** @brief Elapsed frames of all completed laps */
		float LapsElapsedFrames;
		/** @brief Time remaining for join cooldown */
		float JoinCooldownFrames;

		/** @brief Whether the player is in spectate mode */
		SpectateMode IsSpectating;

		PeerDescriptor();
	};
}

#endif