#ifndef _H_ENTITY_H
#define _H_ENTITY_H

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "graphics/shader.h"

class Camera;
struct PhysicsComponent;

class Entity
{
public:
	Entity(const std::shared_ptr<Shader>& shader) :
		shader(shader),
		position(glm::vec3(0.0f)),
		scale(glm::vec3(1.0f)),
		rotation(0.0f),
		speed(5.0f) {};
	virtual ~Entity() {};

	void setPosition(const glm::vec3& position);
	void setScale(const glm::vec3& scale);
	virtual void setRotation(const float& rotation);
	void setLocalPosition(const glm::vec3& localPosition);
	void setRotatable(bool rotatable);

	void flip();

	void addPhysicsComponent(const std::shared_ptr<PhysicsComponent>& physics);

	const glm::vec3& getPosition() const { return this->position; }
	const glm::vec3& getScale() const { return this->scale; }
	const float getRotation() const { return this->rotation; }
	const bool isFlipped() const { return flipped; }
	const glm::vec2 getFacingDir() const { return glm::vec2(cos(glm::radians(rotation)), sin(glm::radians(rotation))); }
	const glm::vec3 getCenter() const { return glm::vec3(position.x + (0.5f * scale.x), position.y + (0.5f * scale.y), 0.0f); }
	const bool getIsMoving() const { return isMoving; }
	const std::shared_ptr<PhysicsComponent> getPhysicsComponent() const { return physics; }

	// TODO: right now there is no default behavior, but eventually the Entity class will be expanded to handle physics
	virtual void update(float deltaTime) = 0;
	virtual void render(const std::shared_ptr<Camera>& camera) = 0;

protected:
	glm::vec3 localPosition;
	glm::vec3 position;
	glm::vec3 deltaPosition; // future position frame, updated in update
	glm::vec3 scale;
	float rotation;
	float speed;

	std::shared_ptr<PhysicsComponent> physics;

	bool isMoving = false;
	bool isRotatable = true;
	bool flipped = false;

	glm::mat4 modelMatrix;

	void updateModelMatrix();

	std::shared_ptr<Shader> shader;
};


#endif //_H_ENTITY_H