#pragma once
#include "Character.h"
#include "render/Renderer.h"
#include "Environment.h"
#include "render/TextureManager.h"
#include "SparkEmitter.h"
#include "UiManager.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 <unordered_map>
#include <unordered_set>
#include "Location.h"
#include "AudioPlayerAsync.h"
namespace ZL {

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

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

		bool shouldExit() const { return Environment::exitGameLoop; }

		Renderer renderer;
		TaskManager taskManager;
		MainThreadHandler mainThreadHandler;

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

		std::unordered_map<std::string, std::shared_ptr<Location>> locations;
		std::shared_ptr<Location> currentLocation;

		bool navigationEditorMode = false;

		// Global darklands state — persists across location transitions.
		bool isDarklands = false;
		// Returns false if a transition is already in progress.
		bool startDarklandsTransition();

		Inventory inventory;
		InteractiveObject* pickedUpObject = nullptr;

		std::unordered_map<std::string, int> globalInts;
		std::unordered_map<std::string, float> globalFloats;

		MenuManager menuManager;
		
		void activateSlowMoEffect();
		
	private:
		// Unified pointer handling: mouse-left and a single touch share one path.
		// A press becomes a tap (interact / walk-to) on release if it never crossed
		// CAMERA_DRAG_PIXEL_THRESHOLD; otherwise it becomes a camera-rotation drag.
		// Two simultaneous touches enter pinch-zoom instead.
		static constexpr int CAMERA_DRAG_PIXEL_THRESHOLD = 12;

		struct PointerState {
			int eventX = 0, eventY = 0;        // current raw window-pixel coords
			int mx = 0, my = 0;                // current projection-space coords
			int downEventX = 0, downEventY = 0;// where the press started (raw px)
			int downMx = 0, downMy = 0;        // where the press started (proj)
			bool capturedByUi = false;
		};
		std::unordered_map<int64_t, PointerState> activePointers;
		bool hasPrimaryPointer = false;
		int64_t primaryPointerId = 0;
		bool cameraDragging = false;

		bool pinchActive = false;
		int64_t pinchFingerA = 0;
		int64_t pinchFingerB = 0;
		float pinchStartDistance = 0.0f;
		float pinchStartZoom = 0.0f;

		std::unique_ptr<AudioPlayerAsync> audioPlayer;

		int64_t getSyncTimeMs();
		void processTickCount();
		void drawScene();
		void drawUI();

		void drawLoading();

		void onPointerDown(int64_t fingerId, int eventX, int eventY, int mx, int my);
		void onPointerUp(int64_t fingerId, int eventX, int eventY, int mx, int my);
		void onPointerMotion(int64_t fingerId, int eventX, int eventY, int mx, int my);

		void enterCameraDragMode(int eventX, int eventY);
		void exitCameraDragMode();
		void startPinch();
		void updatePinchZoom();
		void endPinch();
		int countNonUiPointers() const;

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

		// White-flash transition state
		float darklandsFlashAlpha = 0.0f;
		bool  darklandsFlashActive = false;
		bool  darklandsFlashFadingIn = true;
		VertexRenderStruct darklandsFlashQuad;
		float darklandsFlashQuadW = -1.0f;
		float darklandsFlashQuadH = -1.0f;

		void updateDarklandsFlash(int64_t deltaMs);
		void drawDarklandsFlash();

		int64_t newTickCount;
		int64_t lastTickCount;

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


} // namespace ZL
