#pragma once

#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 "network/NetworkInterface.h"
#include <queue>
#include <vector>
#include <string>
#include <memory>
#include <render/TextRenderer.h>

#include <unordered_set>

namespace ZL {

	
	struct BoxCoords
	{
		Vector3f pos;
		Matrix3f m;
	};


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

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

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

		Renderer renderer;
		TaskManager taskManager;
		MainThreadHandler mainThreadHandler;

		std::unique_ptr<INetworkClient> networkClient;
	private:
		void processTickCount();
		void drawScene();
		void drawCubemap(float skyPercent);
		void drawShip();
		void drawBoxes();
		void drawBoxesLabels();
		void drawUI();
		void drawRemoteShips();
		void drawRemoteShipsLabels();
		void fireProjectiles();

		bool worldToScreen(const Vector3f& world, float& outX, float& outY, float& outDepth) const;

		void handleDown(int mx, int my);
		void handleUp(int mx, int my);
		void handleMotion(int mx, int my);

		SDL_Window* window;
		SDL_GLContext glContext;
		
		

		size_t newTickCount;
		size_t lastTickCount;

		std::vector<BoxCoords> boxCoordsArr;
		std::vector<VertexRenderStruct> boxRenderArr;

		std::vector<std::string> boxLabels;
		std::unique_ptr<TextRenderer> textRenderer;

		//std::unordered_map<int, ClientStateInterval> latestRemotePlayers;
		std::unordered_map<int, ClientState> remotePlayerStates;

		float newShipVelocity = 0;

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

		std::shared_ptr<Texture> sparkTexture;
		std::shared_ptr<Texture> spaceshipTexture;
		std::shared_ptr<Texture> cubemapTexture;
		VertexDataStruct spaceshipBase;
		VertexRenderStruct spaceship;


		VertexRenderStruct cubemap;

		std::shared_ptr<Texture> boxTexture;
		VertexDataStruct boxBase;

		SparkEmitter sparkEmitter;
		SparkEmitter projectileEmitter;
		SparkEmitter explosionEmitter;
		PlanetObject planetObject;
		UiManager uiManager;

		std::vector<std::unique_ptr<Projectile>> projectiles;
		std::shared_ptr<Texture> projectileTexture;
		float projectileCooldownMs = 500.0f;
		uint64_t lastProjectileFireTime = 0;
		int maxProjectiles = 32;
		std::vector<Vector3f> shipLocalEmissionPoints;


		bool shipAlive = true;
		bool gameOver = false;
		std::vector<bool> boxAlive;
		float shipCollisionRadius = 15.0f;
		float boxCollisionRadius = 2.0f;
		bool uiGameOverShown = false;
		bool showExplosion = false;
		uint64_t lastExplosionTime = 0;
		const uint64_t explosionDurationMs = 500;


		bool serverBoxesApplied = false;

		static constexpr float MAX_DIST_SQ = 10000.f * 10000.f;
		static constexpr float FADE_START = 6000.f;
		static constexpr float FADE_RANGE = 4000.f;
		static constexpr float BASE_SCALE = 140.f;
		static constexpr float PERSPECTIVE_K = 0.05f; // Tune
		static constexpr float MIN_SCALE = 0.4f;
		static constexpr float MAX_SCALE = 0.8f;
		static constexpr float CLOSE_DIST = 600.0f;

		std::unordered_set<int> deadRemotePlayers;


	};


} // namespace ZL