#pragma once

#include "NetworkInterface.h"
#include <queue>
#include <vector>
#include <Eigen/Dense>
#include <chrono>
#include <random>

namespace ZL {

	struct LocalServerBox {
		Eigen::Vector3f position;
		Eigen::Matrix3f rotation;
		float collisionRadius = 2.0f;
		bool destroyed = false;
	};

	struct LocalProjectile {
		int shooterId = -1;
		uint64_t spawnMs = 0;
		Eigen::Vector3f pos;
		Eigen::Vector3f vel;
		float lifeMs = 5000.0f;
	};

	struct LocalNPC {
		int id = -1;
		ClientState currentState;
		ClientStateInterval stateHistory;
		Eigen::Vector3f targetPosition;
		uint64_t lastStateUpdateMs = 0;
		bool destroyed = false;
		int shipType = 0;
	};

	class LocalClient : public INetworkClient {
	private:
		std::queue<std::string> messageQueue;
		std::vector<LocalServerBox> serverBoxes;
		std::vector<LocalProjectile> projectiles;
		std::vector<ProjectileInfo> pendingProjectiles;
		std::vector<DeathInfo> pendingDeaths;
		std::vector<BoxDestroyedInfo> pendingBoxDestructions;
		std::vector<BoxPickedUpInfo> pendingBoxPickups;
		std::vector<BoxRespawnInfo> pendingBoxRespawns;
		std::vector<int> pendingRespawns;

		uint64_t lastUpdateMs = 0;
		ClientState localPlayerState;
		bool hasLocalPlayerState = false;

		std::vector<LocalNPC> npcs;

		void updatePhysics();
		void checkCollisions();
		void generateBoxes();
		void initializeNPCs();
		void updateNPCs();
		Eigen::Vector3f generateRandomPosition();
		Eigen::Vector3f generateRespawnBoxPos(int skipIdx);

	public:
		void Connect(const std::string& host, uint16_t port) override;

		void Poll() override;

		void Send(const std::string& message) override;

		bool IsConnected() const override { return true; }
		int GetClientId() const override { return 1; }
		std::vector<ProjectileInfo> getPendingProjectiles() override;

		std::unordered_map<int, ClientStateInterval> getRemotePlayers() override;

		std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override;

		std::vector<DeathInfo> getPendingDeaths() override;

		std::vector<int> getPendingRespawns() override {
			return {};
		}

		std::vector<BoxDestroyedInfo> getPendingBoxDestructions() override;
		std::vector<BoxPickedUpInfo> getPendingBoxPickups() override;
		std::vector<BoxRespawnInfo> getPendingBoxRespawns() override;

		void setLocalPlayerState(const ClientState& state) {
			localPlayerState = state;
			hasLocalPlayerState = true;
		}
	};
}