#pragma once

#include "../Main.h"
#include "LevelInitialization.h"

#if defined(WITH_MULTIPLAYER)
#	include "Multiplayer/ServerInitialization.h"
#endif

#include <Containers/Function.h>

using namespace Death::Containers;

namespace Jazz2
{
	/**
		@brief Base interface of a root controller
		
		Top-level application controller that owns the active state handler and drives transitions between them
		(main menu, levels), manages resumable state, exposes async invocation, and on supported builds connects to
		or hosts a multiplayer server.
	*/
	class IRootController
	{
	public:
		/** @brief State flags of root controller, supports a bitwise combination of its member values */
		enum class Flags {
			None = 0x00,									/**< None */

			IsInitialized = 0x01,							/**< The controller has been initialized */
			IsVerified = 0x02,								/**< The assets have been verified */
			IsPlayable = 0x04,								/**< The game is playable */

#if defined(DEATH_TARGET_ANDROID)
			HasExternalStoragePermission = 0x10,			/**< External storage permission has been granted */
			HasExternalStoragePermissionOnResume = 0x20,	/**< External storage permission should be checked on resume */
#endif
		};

		DEATH_PRIVATE_ENUM_FLAGS(Flags);

		/** @brief Creates a new instance */
		IRootController() { }
		virtual ~IRootController() { }

		IRootController(const IRootController&) = delete;
		IRootController& operator=(const IRootController&) = delete;

		/** @brief Invokes the specified callback asynchronously, usually at the end of current frame */
		virtual void InvokeAsync(Function<void()>&& callback) = 0;
		/** @overload */
		virtual void InvokeAsync(std::weak_ptr<void> reference, Function<void()>&& callback) = 0;
		/** @brief Sets current state handler to main menu */
		virtual void GoToMainMenu(bool afterIntro) = 0;
		/** @brief Sets current state handler to level described by @ref LevelInitialization */
		virtual void ChangeLevel(LevelInitialization&& levelInit) = 0;
		/** @brief Returns `true` if any resumable state exists */
		virtual bool HasResumableState() const = 0;
		/** @brief Resumes saved resumable state */
		virtual void ResumeSavedState() = 0;
		/** @brief Saves current state if it's resumable */
		virtual bool SaveCurrentStateIfAny() = 0;

#if defined(WITH_MULTIPLAYER)
		/** @brief Connects to a multiplayer server asynchronously */
		virtual void ConnectToServer(StringView endpoint, std::uint16_t defaultPort, StringView password = {}) = 0;
		/** @brief Creates a multiplayer server */
		virtual bool CreateServer(Multiplayer::ServerInitialization&& serverInit) = 0;
#endif

		/** @brief Returns current state flags */
		virtual Flags GetFlags() const = 0;
		/** @brief Returns version of the latest update */
		virtual StringView GetNewestVersion() const = 0;

		/** @brief Recreates level cache from `Source` directory */
		virtual void RefreshCacheLevels(bool recreateAll) = 0;
	};
}