//-----------------------------------------------------------------
// Main Game  File
// C++ Header - Game.h - version v8_01			
//-----------------------------------------------------------------

#pragma once

#include <sol/sol.hpp>

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------

#include "Resource.h"	
#include "GameEngine.h"
#include "AbstractGame.h"

//-----------------------------------------------------------------
// Game Class																
//-----------------------------------------------------------------
class Game : public AbstractGame, public Callable
{
public:				
	//---------------------------
	// Constructor(s) and Destructor
	//---------------------------
    Game(const std::string &fileName);

	virtual ~Game() override;

	//---------------------------
	// Disabling copy/move constructors and assignment operators   
	//---------------------------
	Game(const Game& other)					= delete;
	Game(Game&& other) noexcept				= delete;
	Game& operator=(const Game& other)		= delete;
	Game& operator=(Game&& other) noexcept	= delete;

	//---------------------------
	// General Member Functions
	//---------------------------
	void Initialize			()															override;
	void Start				()															override;
	void End				()															override;
	void Paint				(RECT rect)	const											override;
	void Tick				()															override;
	void MouseButtonAction	(bool isLeft, bool isDown, int x, int y, WPARAM wParam)		override;
	void MouseWheelAction	(int x, int y, int distance, WPARAM wParam)					override;
	void MouseMove			(int x, int y, WPARAM wParam)								override;
	void CheckKeyboard		()															override;
	void KeyPressed			(TCHAR key)													override;
	
	void CallAction			(Caller* callerPtr)											override;
    void InitialiseBindings ()                                                          override;

//    std::string GetRequest(std::string url);

    template <typename ReturnType = void, typename... Args>
    ReturnType FunctionCall(const std::string &functionName, Args&&... args) const {
        auto func = m_state[functionName];
        sol::protected_function_result func_return;

        if constexpr (sizeof...(Args) == 0) {
            func_return = func();
        } else {
            func_return = func(std::forward<Args>(args)...);
        }

        if (!func_return.valid()) {
            const sol::error err = func_return;
            std::cerr << "Function Call Error: " << err.what();
            GAME_ENGINE->MessageBox(err.what());
            throw std::runtime_error(err.what());
        }

        if constexpr (!std::is_void_v<ReturnType>) {
            try {
                return func_return.get<ReturnType>();
            } catch (const sol::error& err) {
                std::cerr << "Return Value Error: " << err.what();
                GAME_ENGINE->MessageBox(err.what());
            }
        }

        return ReturnType{};
    }
private:
	// -------------------------
	// Datamembers
	// -------------------------

    sol::state m_state;
    std::string m_fileName;

    std::unordered_map<std::string, char> m_specialKeys;
};
