#include "game/engine/player_camera.hpp"

using namespace polygun::engine;

static float mx,my;

Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch) :
	m_position(position),
	m_front(glm::vec3(0.0f, 0.0f, -1.0f)),
	m_up(),
	m_right(),
	m_worldup(up),
	m_yaw(yaw),
	m_pitch(pitch),
	m_movement_speed(SPEED),
	m_mouse_sensitivity(SENSITIVITY),
	m_zoom(ZOOM),
	m_last_x(SCR_WIDTH / 2.0f),
	m_last_y(SCR_HEIGHT / 2.0f),
	m_first_mouse(true)
{
	update_camera_vectors();
}

Camera::Camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float yaw, float pitch) :
	m_position(pos_x, pos_y, pos_z),
	m_front(glm::vec3(0.0f, 0.0f, -1.0f)),
	m_up(),
	m_right(),
	m_worldup(up_x, up_y, up_z),
	m_yaw(yaw),
	m_pitch(pitch),
	m_movement_speed(SPEED),
	m_mouse_sensitivity(SENSITIVITY),
	m_zoom(ZOOM),
	m_last_x(SCR_WIDTH / 2.0f),
	m_last_y(SCR_HEIGHT / 2.0f),
	m_first_mouse(true)
{
	update_camera_vectors();
}

void Camera::update() {
	if (m_first_mouse) {
		m_last_x = mx;
		m_last_y = my;
		m_first_mouse = false;
	}

	float x_offset = mx - m_last_x;
	float y_offset = m_last_y - my; 

	m_last_x = mx;
	m_last_y = my;

	process_mouse_movement(x_offset, y_offset);
}

void Camera::process_movement(camera_movement direction, float delta_time) {
	float velocity = m_movement_speed * delta_time;
	if (direction == FORWARD)
		m_position += m_front * velocity;
	if (direction == BACKWARD)
		m_position -= m_front * velocity;
	if (direction == LEFT)
		m_position -= m_right * velocity;
	if (direction == RIGHT)
		m_position += m_right * velocity;
	if (direction == UP)
		m_position += glm::vec3(0.0F, 1.0F, 0.0F) * velocity;
	if (direction == DOWN)
		m_position += glm::vec3(0.0F, -1.0F, 0.0F) * velocity;
}

void Camera::process_mouse_movement(float x_offset, float y_offset, GLboolean constrain_pitch) {
	x_offset *= m_mouse_sensitivity;
	y_offset *= m_mouse_sensitivity;

	m_yaw   += x_offset;
	m_pitch += y_offset;

	if (constrain_pitch) {
		if (m_pitch > 89.0f)
			m_pitch = 89.0f;
		if (m_pitch < -89.0f)
			m_pitch = -89.0f;
	}

	update_camera_vectors();
}

void Camera::process_mouse_scroll(float y_offset) {
	m_zoom -= y_offset;
	if (m_zoom < 1.0f)
		m_zoom = 1.0f;
	if (m_zoom > 45.0f)
		m_zoom = 45.0f;
}

void Camera::mouse_callback(GLFWwindow* window, double x_pos_in, double y_pos_in) {
	mx = static_cast<float>(x_pos_in);
	my = static_cast<float>(y_pos_in);
}

void Camera::update_camera_vectors() {
	glm::vec3 front;
	front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
	front.y = sin(glm::radians(m_pitch));
	front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
	m_front = glm::normalize(front);
	m_right = glm::normalize(glm::cross(m_front, m_worldup));  
	m_up    = glm::normalize(glm::cross(m_right, m_front));
}
