#pragma once
#include "Character.h"
#include "BoneAnimatedModel.h"
#include "render/Renderer.h"
#include "Environment.h"
#include "render/TextureManager.h"
#include "SparkEmitter.h"
#include "planet/PlanetObject.h"
#include "UiManager.h"
#include "Projectile.h"
#include "utils/TaskManager.h"
#include "items/GameObjectLoader.h"
#include "items/Item.h"
#include "items/InteractiveObject.h"
#include <queue>
#include <vector>
#include <string>
#include <memory>
#include <cstdint>
#include <render/TextRenderer.h>
#include "MenuManager.h"
#include "ScriptEngine.h"
#include <unordered_map>
#include "dialogue/DialogueSystem.h"
#include "render/ShadowMap.h"
#include "navigation/PathFinder.h"
#include <unordered_set>

namespace ZL {

	class Game {
	public:
		Game();
		~Game();

		void setup();
		void setupPart2();
		void update();
		void render();

		bool shouldExit() const { return Environment::exitGameLoop; }
		bool requestDialogueStart(const std::string& dialogueId);
		void setDialogueFlag(const std::string& flag, int value);
		int getDialogueFlag(const std::string& flag) const;
		bool setNavigationAreaAvailable(const std::string& areaName, bool available);

		Renderer renderer;
		TaskManager taskManager;
		MainThreadHandler mainThreadHandler;
		//std::unique_ptr<INetworkClient> networkClient;
		

		std::shared_ptr<Texture> loadingTexture;
		VertexRenderStruct loadingMesh;
		bool loadingCompleted = false;


		std::shared_ptr<Texture> roomTexture;
		VertexRenderStruct roomMesh;

		std::unordered_map<std::string, LoadedGameObject> gameObjects;

		/*
		std::shared_ptr<Texture> fireboxTexture;
		VertexRenderStruct fireboxMesh; 
		
		std::shared_ptr<Texture> inaiTexture;
		VertexRenderStruct inaiMesh;

		std::shared_ptr<Texture> benchTexture;
		VertexRenderStruct benchMesh;
		*/
		std::vector<InteractiveObject> interactiveObjects;
		Inventory inventory;
		InteractiveObject* pickedUpObject = nullptr;

		// Interactive object targeting
		InteractiveObject* targetInteractiveObject = nullptr;
		bool inventoryOpen = false;

		std::unique_ptr<Character> player;
		std::vector<std::unique_ptr<Character>> npcs;

		float cameraAzimuth = 0.0f;
		float cameraInclination = M_PI * 30.f / 180.f;

		// Public access for ScriptEngine
		MenuManager menuManager;
		ScriptEngine scriptEngine;
		PathFinder navigation;

#ifdef SHOW_PATH
		std::vector<VertexRenderStruct> debugNavMeshes;
#endif

	private:
		bool rightMouseDown = false;
		int lastMouseX = 0;
		int lastMouseY = 0;

		static constexpr float CAMERA_FOV_Y = 1.0f / 1.5f;

		int64_t getSyncTimeMs();
		void processTickCount();
		void drawScene();
		void drawUI();
		void drawGame();
		void drawLoading();
		void drawShadowDepthPass();
		void drawGameWithShadows();
		void setupNavigation();
		void handleDown(int64_t fingerId, int mx, int my);
		void handleUp(int64_t fingerId, int mx, int my);
		void handleMotion(int64_t fingerId, int mx, int my);
		InteractiveObject* raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir);
		Character* raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance = 100.0f);

#ifdef SHOW_PATH
		void buildDebugNavMeshes();
		void drawDebugNavigation();
#endif

#ifdef EMSCRIPTEN
		static Game* s_instance;
		static void onResourcesZipLoaded(const char* filename);
		static void onResourcesZipError(const char* filename);
#endif

		int64_t newTickCount;
		int64_t lastTickCount;
		uint32_t connectingStartTicks = 0;
		static constexpr uint32_t CONNECTING_TIMEOUT_MS = 10000;

		static const size_t CONST_TIMER_INTERVAL = 10;
		static const size_t CONST_MAX_TIME_INTERVAL = 1000;

		//MenuManager menuManager;
		Dialogue::DialogueSystem dialogueSystem;
		//ScriptEngine scriptEngine;

		std::unique_ptr<ShadowMap> shadowMap;
		Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity();
	};


} // namespace ZL
