#include "Morault_Player.h"
#include <raymath.h>


Morault::Gameplay::Player::Player()
{
}

Morault::Gameplay::Player::Player(PlayerData a, PlayerController b)
{
	data = a; controller = b; // self explanatory <3
}

Morault::Gameplay::Player::~Player()
{
}

Morault::Gameplay::PlayerController::PlayerController()
{
	camera = { 0 };
	camera.fovy = 90;
	camera.position = { -10,5,0 };
	camera.target = { 0,5,0 };
	camera.up = { 0,1,0 };
	camera.projection = CAMERA_PERSPECTIVE;
	rotation = { 10,0,0 };
}

Morault::Gameplay::PlayerController::PlayerController(Vector3 position)
{
	camera = { 0 };
	camera.fovy = 90;
	camera.position = position;
	camera.target = { 0, position.y,0 };
	camera.up = { 0,1,0 };
	camera.projection = CAMERA_PERSPECTIVE;
	rotation = { 1,0,0 };
}
float collfloor = 5;
float collceiling = INFINITY;

float gravity = 0;

bool qColl(float obesity, Vector3 futurePos, Morault::Maps::Map* map, float renderScale, Vector3 velocity) {
	int currsec = -1;
	Vector2 normalizedVelocity = Vector2Normalize({ velocity.x, velocity.z });
	for (int i = 0; i < map->MapTriangles.size(); i++) {

		if (CheckCollisionPointTriangle({ futurePos.x / renderScale, futurePos.z / renderScale }, map->MapTriangles[i].a, map->MapTriangles[i].b, map->MapTriangles[i].c)) {
			currsec = i;
		}
	}
	if (currsec == -1) return true;

	for (int i = 0; i < map->MapTriangles.size(); i++) {
		// check wall collisions
		if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, 100.0f, Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale })) || CheckCollisionCircleLine({ futurePos.x, futurePos.z }, 300.0f, Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale })) || CheckCollisionCircleLine({ futurePos.x, futurePos.z }, 300.0f, Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }))) {

			if (map->MapTriangles[i].wallAB != "pms:none") {
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }))) {
					// futurePos = camera.position;
					return true;
				}
			}
			if (map->MapTriangles[i].wallBC != "pms:none") {
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }))) {

					return true;
				}
			}
			if (map->MapTriangles[i].wallCA != "pms:none") {
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }))) {

					return true;
				}
			}
			if (map->MapTriangles[i].heightFloor > map->MapTriangles[currsec].heightFloor) {
				int highestFloor = map->MapTriangles[i].heightFloor < map->MapTriangles[currsec].heightFloor ? map->MapTriangles[currsec].heightFloor : map->MapTriangles[i].heightFloor;
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].a, { renderScale, renderScale }), Vector2Multiply(map->MapTriangles[i].b, { renderScale, renderScale }))) {
					if (Vector2DotProduct({ -(map->MapTriangles[i].b.y - map->MapTriangles[i].a.y), (map->MapTriangles[i].b.x - map->MapTriangles[i].a.x) }, normalizedVelocity) > 0) {
						
					}
					else {


						if (futurePos.y - 5 > highestFloor * renderScale) {

						}
						else return true;
					}
				}
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].b, { renderScale, renderScale }), Vector2Multiply(map->MapTriangles[i].c, { renderScale, renderScale }))) {
					if (Vector2DotProduct({ -(map->MapTriangles[i].c.y - map->MapTriangles[i].b.y), (map->MapTriangles[i].c.x - map->MapTriangles[i].b.x) }, normalizedVelocity) > 0) {

					}
					else {


						if (futurePos.y - 5 > highestFloor * renderScale) {

						}
						else return true;
					}
				}
				if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].c, { renderScale, renderScale }), Vector2Multiply(map->MapTriangles[i].a, { renderScale, renderScale }))) {
					if (Vector2DotProduct({ -(map->MapTriangles[i].a.y - map->MapTriangles[i].c.y), (map->MapTriangles[i].a.x - map->MapTriangles[i].c.x) }, normalizedVelocity) > 0) {

					}
					else {


						if (futurePos.y - 5 > highestFloor * renderScale) {

						}
						else return true;
					}
				}
			}

		}

	}
	return false;
}

void Morault::Gameplay::PlayerController::UpdatePlayerController(bool focus, Morault::Maps::Map* map, float renderScale)
{

	Vector3 futurePos = camera.position;
	bool correctionNecessary = false;
	if (focus) {
		rotation = Vector3RotateByAxisAngle(rotation, { 0,1,0 }, -GetMouseDelta().x * 0.05 * sensitivityMultiplier);
		rotation.y = Clamp(rotation.y - GetMouseDelta().y * 0.3 * sensitivityMultiplier, -15, 15);
		
		
		if (IsKeyDown(KEY_W)) futurePos = Vector3Add(futurePos, Vector3Multiply({rotation.x, 0, rotation.z}, {GetFrameTime(), GetFrameTime(), GetFrameTime()}));
		if (IsKeyDown(KEY_S)) futurePos = Vector3Subtract(futurePos, Vector3Multiply({ rotation.x, 0, rotation.z }, { GetFrameTime(), GetFrameTime(), GetFrameTime() }));

		if (IsKeyDown(KEY_A)) futurePos = Vector3Add(futurePos, Vector3Multiply(Vector3RotateByAxisAngle({ rotation.x, 0, rotation.z }, {0,1,0}, DEG2RAD*90), {GetFrameTime(), GetFrameTime(), GetFrameTime()}));
		if (IsKeyDown(KEY_D)) futurePos = Vector3Add(futurePos, Vector3Multiply(Vector3RotateByAxisAngle({ rotation.x, 0, rotation.z }, { 0,1,0 }, DEG2RAD * -90), { GetFrameTime(), GetFrameTime(), GetFrameTime() }));
		if (IsKeyPressed(KEY_SPACE)) {
			gravity -= 10;
		}
		
		
	}
	else {
		rotation = { 0,0,0 };
	}

	int currsec = -1;

	for (int i = 0; i < map->MapTriangles.size(); i++) {

		if (CheckCollisionPointTriangle({ futurePos.x / renderScale, futurePos.z / renderScale }, map->MapTriangles[i].a, map->MapTriangles[i].b, map->MapTriangles[i].c)) {
			collfloor = map->MapTriangles[i].heightFloor * renderScale + 5;
			collceiling = map->MapTriangles[i].heightCeiling * renderScale - 2;
			currsec = i;
		}
	}
	if(currsec != -1){
		for (int i = 0; i < map->MapTriangles.size(); i++) {
			// check wall collisions
			if (CheckCollisionCircleLine({futurePos.x, futurePos.z}, 300.0f, Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale })) || CheckCollisionCircleLine({ futurePos.x, futurePos.z }, 300.0f, Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale })) || CheckCollisionCircleLine({ futurePos.x, futurePos.z }, 300.0f, Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }))) {
				
				if (map->MapTriangles[i].wallAB != "pms:none" || (map->MapTriangles[currsec].heightFloor < map->MapTriangles[i].heightFloor ? abs(abs(map->MapTriangles[currsec].heightFloor) - abs(map->MapTriangles[i].heightFloor)) > 10 : false)) {
					if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }))) {
						// futurePos = camera.position;
						correctionNecessary = true;
					}
				}
				if (map->MapTriangles[i].wallBC != "pms:none" || (map->MapTriangles[currsec].heightFloor < map->MapTriangles[i].heightFloor ? abs(abs(map->MapTriangles[currsec].heightFloor) - abs(map->MapTriangles[i].heightFloor)) > 10 : false)) {
					if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].b, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }))) {

						correctionNecessary = true;
					}
				}
				if (map->MapTriangles[i].wallCA != "pms:none" || (map->MapTriangles[currsec].heightFloor < map->MapTriangles[i].heightFloor ? abs(abs(map->MapTriangles[currsec].heightFloor) - abs(map->MapTriangles[i].heightFloor)) > 10 : false)) {
					if (CheckCollisionCircleLine({ futurePos.x, futurePos.z }, obesity, Vector2Multiply(map->MapTriangles[i].c, { renderScale,renderScale }), Vector2Multiply(map->MapTriangles[i].a, { renderScale,renderScale }))) {

						correctionNecessary = true;
					}
				}
			}

		}
	}
	
	if (correctionNecessary) {
		if (!qColl(obesity, futurePos, map, renderScale, Vector3Subtract(futurePos, camera.position))) futurePos = futurePos;

		// else if (!qColl(obesity, Vector3Add(futurePos, Vector3Multiply(Vector3Subtract(camera.target, camera.position), {0.5, 0.5, 0.5})), map, renderScale, Vector3Subtract(futurePos, camera.position))) futurePos = Vector3Add(futurePos, Vector3Multiply(Vector3Subtract(camera.target, camera.position), { 0.01, 0.01, 0.01 }));
		else futurePos = camera.position;
	}

	futurePos.y -= gravity*GetFrameTime();
	gravity += 10*GetFrameTime();
	if (futurePos.y < collfloor) {
		futurePos.y = collfloor;
		gravity = 0;
	}
	if (futurePos.y > collceiling) {
		futurePos.y = collceiling;
		gravity = 0;
	}
	camera.position = futurePos;
	


	camera.target = Vector3Add(camera.position, rotation);
}

Morault::Gameplay::PlayerController::~PlayerController()
{
	camera = { 0 };
}
