#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 "MenuManager.h"

#include <unordered_set>

namespace ZL {


	struct BoxCoords
	{
		Vector3f pos;
		Matrix3f m;
	};


	class Space {
	public:
		Space(Renderer& iRenderer, TaskManager& iTaskManager, MainThreadHandler& iMainThreadHandler, std::unique_ptr<INetworkClient>& iNetworkClient, MenuManager& iMenuManager);
		~Space();

		void setup();
		void update();

		Renderer& renderer;
		TaskManager& taskManager;
		MainThreadHandler& mainThreadHandler;
		std::unique_ptr<INetworkClient>& networkClient;
		MenuManager& menuManager;


	public:
		void processTickCount(int64_t newTickCount, int64_t delta);
		void drawScene();
		void drawCubemap(float skyPercent);
		void drawShip();
		void drawBoxes();
		void drawBoxesLabels();
		void drawRemoteShips();
		void drawRemoteShipsLabels();
		void fireProjectiles();

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


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

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

		std::unordered_map<int, ClientState> remotePlayerStates;
	std::unordered_map<int, SparkEmitter> remoteShipSparkEmitters;

		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;

		std::shared_ptr<Texture> cargoTexture;
		VertexDataStruct cargoBase;
		VertexRenderStruct cargo;

		VertexRenderStruct cubemap;

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

		SparkEmitter sparkEmitter;
		SparkEmitter sparkEmitterCargo;
		SparkEmitter projectileEmitter;
		SparkEmitter explosionEmitter;
		PlanetObject planetObject;

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


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

		bool serverBoxesApplied = false;
		bool nearPickupBox = 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;
		int playerScore = 0;
		int prevPlayerScore = 0;
		bool wasConnectedToServer = false;

		bool playerListVisible = false;
		int manualTrackedTargetId = -1;

		static constexpr float TARGET_MAX_DIST = 50000.0f;
		static constexpr float TARGET_MAX_DIST_SQ = TARGET_MAX_DIST * TARGET_MAX_DIST;

		// --- Target HUD (brackets + offscreen arrow) ---
		int trackedTargetId = -1;
		bool targetWasVisible = false;
		float targetAcquireAnim = 0.0f;   // 0..1 схлопывание (0 = далеко, 1 = на месте)

		// временный меш для HUD (будем перезаливать VBO маленькими порциями)
		VertexRenderStruct hudTempMesh;

		// helpers
		void drawTargetHud(); // рисует рамку или стрелку
		int pickTargetId() const; // ???????? ???? (????: ????????? ????? ????????? ?????)

		void resetPlayerState();
		void clearTextRendererCache();
		void updateShowPlayersButtonState();
		bool showPlayersButtonEnabled = false;

		// Player list overlay
		void buildAndShowPlayerList();
		void closePlayerList();
		void rebuildPlayerListIfVisible();
		void clearPlayerListIfVisible();
		std::shared_ptr<UiNode> buildPlayerListRoot();

		void updateSparkEmitters(float deltaMs);
		void prepareSparkEmittersForDraw();
		void drawShipSparkEmitters();

		// Crosshair HUD
		struct CrosshairConfig {
			bool enabled = true;
			int refW = 1280;
			int refH = 720;
			
			float scaleMul = 1.0f;

			Eigen::Vector3f color = { 1.f, 1.f, 1.f };
			float alpha = 1.0f;       // cl_crosshairalpha
			float thicknessPx = 2.0f; // cl_crosshairthickness
			float gapPx = 10.0f;

			float topLenPx = 14.0f;
			float topAngleDeg = 90.0f;

			struct Arm { float lenPx; float angleDeg; };
			std::vector<Arm> arms;
		};

		CrosshairConfig crosshairCfg;
		bool crosshairCfgLoaded = false;

		// кеш геометрии
		VertexRenderStruct crosshairMesh;
		bool crosshairMeshValid = false;
		int crosshairLastW = 0, crosshairLastH = 0;
		float crosshairLastAlpha = -1.0f;
		float crosshairLastThickness = -1.0f;
		float crosshairLastGap = -1.0f;
		float crosshairLastScaleMul = -1.0f;

		bool loadCrosshairConfig(const std::string& path);
		void rebuildCrosshairMeshIfNeeded();
		void drawCrosshair();
	};


} // namespace ZL