#ifndef _H_PHYSICS_H
#define _H_PHYSICS_H

#include <glm/glm.hpp>
#include <vector>
#include <memory>

class EventManager;

struct PhysicsComponent {
	bool isBullet = false;
	// This ID holds the ID of the gameactor that owns this object, that being themselves or a bullet.
	unsigned int ID = 0; // If the ID stays 0 then that object has no owner and will be uncollidable
	struct RigidBody {
		glm::vec2 position;
		glm::vec2 velocity = glm::vec2(0.f);
		glm::vec2 acceleration = glm::vec2(0.f);
		float elasticity = 0.7f;
		float mass = 1.0f;
		void applyForce(glm::vec2 dir, float mag) { 
			acceleration += ((dir * mag) / mass);
		}
	}rigidBody;

	struct Collider {
		enum class Shape { Square, Circle } shape = Shape::Circle;
		glm::vec2 offset = glm::vec2(0.f);
		glm::vec2 dimensions;
	}collider;
};

class PhysicsComponentFactory {
public:
	static PhysicsComponent makeBullet(const unsigned int ID, const glm::vec3& pos, float mass, float radius) {
		PhysicsComponent p;
		p.ID = ID;
		p.rigidBody.position = pos;
		p.rigidBody.mass = mass;
		p.collider = { PhysicsComponent::Collider::Shape::Circle, glm::vec2(0.f, 0.f), glm::vec2(radius) };
		p.isBullet = true;
		return p;
	}
};

class PhysicsEngine {
public:
	PhysicsEngine() {}

	using CollisionPair = std::pair<PhysicsComponent*, PhysicsComponent*>;

	void hookEventManager(const std::shared_ptr<EventManager>& eventManager);

	std::shared_ptr<PhysicsComponent> createObject(const unsigned int ID, const glm::vec3& pos, float mass, PhysicsComponent::Collider::Shape shape, glm::vec3 dimensions, glm::vec3 offset = glm::vec3(0.f));
	void loadCollisionMap(const std::vector<std::vector<int>>&, float tileSize);
	void addObject(const std::shared_ptr<PhysicsComponent>&);
	void removeObject(const std::shared_ptr<PhysicsComponent>&);
	void update(double deltaTime);
private:
	void resolveWorldCollision(const std::shared_ptr<PhysicsComponent>&);
	void resolvePossibleCollisions();
	void getPossibleCollisions();
	int getTileCollider(const glm::vec2& position);
	std::vector<std::shared_ptr<PhysicsComponent>> objects;
	std::vector<CollisionPair> objCollisions;
	std::vector<std::vector<int>> collisionMap;
	float tileSize = 32.f;
	std::shared_ptr<EventManager> eventManager;
};

#endif //_H_PHYSICS_H
