#include "gameplay/gameactor.h"
#include "gameplay/entity.h"
#include "gameplay/physics.h"
#include "gameplay/weapons/weapon.h"
#include "utility/events.h"
#include "utility/direction.h"
#include "utility/component.h"

GameActor::~GameActor() { }

void GameActor::addComponent(std::shared_ptr<Component> component)
{
	component->ownerid = actorid;
	components.push_back(component);
}

const std::shared_ptr<Weapon>& GameActor::getHeldWeapon() const
{
	return currentWeapon;
}

void GameActor::equipWeapon(std::shared_ptr<Weapon> weapon)
{
	currentWeapon = std::move(weapon);
	if (currentWeapon)
		currentWeapon->setWielder(std::shared_ptr<GameActor>(this));
}

void GameActor::attachEventManager(std::shared_ptr<EventManager> eventManager)
{
	this->eventManager = eventManager;
}

void GameActor::setRotation(const float& rotation) 
{
	if (!isRotatable && eventManager) {
		Direction newDir = getDirectionFromRotation(rotation);
		if (getDirectionFromRotation(this->rotation) != newDir)
			eventManager->notify(std::make_shared<DirectionChangeEvent>(actorid, newDir));
	}
	this->rotation = rotation;
	updateModelMatrix();
}

void GameActor::update(float deltaTime)
{
	Entity::update(deltaTime);

	for (auto& component : components)
		component->update();
	if (currentWeapon)
		currentWeapon->update(deltaTime);
}

void GameActor::render(const std::shared_ptr<Camera>& camera)
{
	Entity::render(camera);

	for (auto& component : components)
	{
		if (isMoving)
			component->play();
		else
			component->idle();
		component->bind();
		component->render();
	}
	if (currentWeapon)
		currentWeapon->render(camera);
	isMoving = false;
}

void GameActor::moveUp()   { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f,-1.f, 0.f), 1500.25f); isMoving = true; }
void GameActor::moveDown() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f, 1.f, 0.f), 1500.25f); isMoving = true; }
void GameActor::moveLeft() { if (physics) physics->rigidBody.applyForce(glm::vec3(-1.f, 0.f, 0.f), 1500.25f); isMoving = true; }
void GameActor::moveRight(){ if (physics) physics->rigidBody.applyForce(glm::vec3( 1.f, 0.f, 0.f), 1500.25f); isMoving = true; }

// top-down shooter mode controls
void GameActor::strafeLeft()	 { position.x += sin(glm::radians(rotation)) * speed; position.y -=  cos(glm::radians(rotation)) * speed; }
void GameActor::strafeRight()	 { position.x -= sin(glm::radians(rotation)) * speed; position.y +=  cos(glm::radians(rotation)) * speed; }
void GameActor::moveBackward()   { position.x -= cos(glm::radians(rotation)) * speed; position.y -=  sin(glm::radians(rotation)) * speed; }
void GameActor::moveForward()	 { if (physics) physics->rigidBody.applyForce(glm::vec3(cos(glm::radians(rotation)), sin(glm::radians(rotation)), 0.f), 1000.f); isMoving = true; }
void GameActor::fireWeapon()	 { if (currentWeapon) currentWeapon->shoot(); }
void GameActor::followMouse(const MouseState& mouse_state) 
{ 
	glm::vec2 direction = glm::vec2(mouse_state.x, mouse_state.y) - glm::vec2(localPosition.x + 0.5f * scale.x, localPosition.y + 0.5f * scale.y);
	float newRotation = glm::degrees(glm::atan(direction.y, direction.x));
	if (getDirectionFromRotation(rotation) != getDirectionFromRotation(newRotation))
		if (eventManager)
			eventManager->notify(std::make_shared<DirectionChangeEvent>(actorid, getDirectionFromRotation(newRotation)));
	//setRotation(glm::degrees(glm::atan(direction.y, direction.x))); 
	this->rotation = newRotation;
}
