#pragma once

#include "definitions.h"
#include "EditorNew.h"
#include "Engine.h"
#include "gl/Buffer.h"
// #include "math/Math.h"
#include "engine/IO.h"
// #include "../math/Math.h"


enum class CameraMode {
	PILOT,
	LOOKAT
};
enum class CameraProjection {
	ORTHOGRAPHIC,
	PERSPECTIVE
};

// struct CameraDescriptor{
// 	glm::vec3 pos = glm::vec3(3.2, 2.4, 0.225);
// 	glm::vec3 look_at = glm::vec3(0, 0, 0);
// 	glm::vec3 pitch_yaw_roll = glm::vec3(0, -acos(-1.0) / 2, 0);
// 	CameraMode mode = CameraMode::PILOT;
// };

struct Camera {
	public:
		// Matrix<float> look_at_mat = Matrix<float>({});
		glm::mat4 look_at_mat = glm::mat4(1);

		static constexpr float radical_inverse[32] = {
			-1, -1, 0, -0.333333, -0.5, 0.333333, 0.5, -0.777778, -0.75, -0.111111, 0.25, 0.555556, -0.25,
			-0.555556, 0.75, 0.111111, -0.875, 0.777778, 0.125, -0.925926, -0.375, -0.259259, 0.625, 0.407407, -0.625,
			-0.703704,
			0.375, -0.037037, -0.125, 0.62963, 0.875, -0.481481
		};

		bool walking_locked = true;
		bool looking_locked = false;
		bool noclip = false;

		CameraProjection camera_projection = CameraProjection::PERSPECTIVE;

		// Vec3 pos = Vec3({0.0, 6.479, 0});
		glm::vec3 prev_pos = glm::vec3(3.2, 2.4, 0.225);
		glm::vec3 prev_right = glm::vec3(0, 0, 0);
	
		glm::vec3 pos = glm::vec3(3.2, 2.4, 0.225);
	
		glm::vec3 look_at = glm::vec3(0, 0, 0);
		glm::vec3 pitch_yaw_roll = glm::vec3(0, -acos(-1.0) / 2, 0);
		float roll = 0.0f;

		glm::vec3 dir = glm::vec3(0, 0, 0);
		glm::vec3 right = glm::vec3(0, 0, 0);
		glm::vec3 up = glm::vec3(0, 0, 0);
		glm::vec3 world_up = glm::vec3(0, 1, 0);

		glm::mat4 V_prev = glm::mat4(1);
		glm::mat4 P_prev = glm::mat4(1);
		//
		glm::mat4  transformation_matrix = glm::mat4(1);
		glm::mat4  V = glm::mat4(1);
		glm::mat4  P = glm::mat4(1);
		//
		glm::mat4  V_inv = glm::mat4(1);
		glm::mat4  P_inv = glm::mat4(1);

		float interp_fac_persp_orth = 0.0f;

		// glm::mat4  V_prev;
		// glm::mat4  P_prev;
		//
		// Matrix<float> transformation_matrix = Matrix<float>({});
		// Matrix<float> V = Matrix<float>({});
		// Matrix<float> P = Matrix<float>({});
		//
		// Matrix<float> V_inv = Matrix<float>({});
		// Matrix<float> P_inv = Matrix<float>({});


		bool camera_moved_this_frame = false;

		CameraMode mode = CameraMode::PILOT;

		float taa_jitt_amt = 0.;

		float curr_offs_x = 0.0;
		float curr_offs_y = 0.0;

		float curr_jitt_x = 0.0;
		float curr_jitt_y = 0.0;
		float prev_jitt_x = 0.0;
		float prev_jitt_y = 0.0;

		// float offs_x = 0.0;
		// float offs_y = 0.0;
		glm::vec2 viewspace_offs = glm::vec2(0);

		float fov = 0.7;
		float _near = 0.03;
		float _far = 125.0;

		float speed = 1.0;

		float t_since_shake = 10000.;

		bool scale_orth_fov_with_cam_pos = true;

		void shake();

		// Camera();

		void update_matrices();

		void handle_movement();
	
		void unuse();

		void use();

		void update();

		glm::vec3 worldspace_to_ndc(glm::vec3 p);
		void lerp_with_another_cam(Camera* other_camera, float lerp_fac);
};

