////////////////////////////////////////////////////////////////////////////////
// Filename: cameraclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _CAMERACLASS_H_
#define _CAMERACLASS_H_


//////////////
// INCLUDES //
//////////////
#include <directxmath.h>

#include "input_class.h"
#include "macro.h"
using namespace DirectX;


////////////////////////////////////////////////////////////////////////////////
// Class name: camera_class
////////////////////////////////////////////////////////////////////////////////
class camera_class
{
public:
	/**
	 * @brief Default constructor for camera_class.
	 * Initializes the camera position and rotation to zero.
	 */
	camera_class();
	camera_class(const camera_class&);
	~camera_class();

	/** 
	 * @brief Sets the position of the camera in 3D space.
	 * 
	 * @param position_x The x-coordinate of the camera's position.
	 * @param position_y The y-coordinate of the camera's position.
	 * @param position_z The z-coordinate of the camera's position.
	 */
	void set_position(float, float, float);
	/**
	 * @brief Sets the rotation of the camera in 3D space.
	 * 
	 * @param rotation_x The rotation around the x-axis in degrees.
	 * @param rotation_y The rotation around the y-axis in degrees.
	 * @param rotation_z The rotation around the z-axis in degrees.
	 */
	void set_rotation(float, float, float);

	/**
	 * @brief Gets the current position of the camera.
	 * 
	 * @return A 3D vector representing the camera's position.
	 */
	XMFLOAT3 get_position();
	/**
	 * @brief Gets the current rotation of the camera.
	 * 
	 * @return A 3D vector representing the camera's rotation in degrees.
	 */
	XMFLOAT3 get_rotation();


	/**
	 * @brief Updates the camera's view matrix based on its position and rotation.
	 * This method recalculates the view matrix to reflect the current camera state.
	 */
	void render();
	/**
	 * @brief Retrieves the current view matrix of the camera.
	 * 
	 * @return The view matrix representing the camera's orientation and position.
	 */
	XMMATRIX get_view_matrix(XMMATRIX& view_matrix) const;

	/**
	 * Update the camera's view matrix without 
	 */

	/**
	 * @brief Renders the reflection of the scene from the camera's perspective.
	 * 
	 * @param reflection_plane_y The y-coordinate of the reflection plane.
	 */
	void render_reflection(float);
	/**
	 * @brief Retrieves the reflection view matrix of the camera.
	 * 
	 * @param reflection_view_matrix The matrix to store the reflection view matrix.
	 */
	void get_reflection_view_matrix(XMMATRIX&) const;


	/**
	 * @brief Calculates and returns the forward direction vector of the camera based on its rotation.
	 * This vector points in the direction the camera is facing.
	 * @return A normalized 3D vector representing the camera's forward direction.
	 */
	XMFLOAT3 get_forward() const {
		float pitch = XMConvertToRadians(rotation_x_);
		float yaw = XMConvertToRadians(rotation_y_);
		XMMATRIX rotMatrix = XMMatrixRotationRollPitchYaw(pitch, yaw, 0.0f);
		XMVECTOR forward = -rotMatrix.r[2];
		forward = XMVector3Normalize(forward);
		XMFLOAT3 forwardVec;
		XMStoreFloat3(&forwardVec, forward);
		return forwardVec;
	}

	/**
	 * @brief Calculates and returns the right direction vector of the camera based on its rotation.
	 * This vector points to the right side of the camera.
	 * @return A normalized 3D vector representing the camera's right direction.
	 */
	XMFLOAT3 get_up() const {
		// Construire matrice rotation à partir des angles
		XMMATRIX rot = XMMatrixRotationRollPitchYaw(
			XMConvertToRadians(rotation_x_),
			XMConvertToRadians(rotation_y_),
			XMConvertToRadians(rotation_z_));

		// Extraire le vecteur up, 2e colonne
		XMVECTOR up = rot.r[1];  // colonne up
		up = XMVector3Normalize(up);

		XMFLOAT3 upF;
		XMStoreFloat3(&upF, up);
		return upF;
	}

	/**
	 * Move the camera
	 * @param std::vector<bool> inputs : forward, backward, left, right, up, down, scrollUp, scrollDown, rightClick
	 * @param float deltaTime : time since last frame
	 * @return void
	 */
	void move(float deltatime, float delta_x, float delta_y);

	/**
	 * Rotate the camera
	 * @param float delta_x : mouse delta x
	 * @param float delta_y : mouse delta y
	 * @return void
	 */
	void rotate(float delta_x, float delta_y);

	/**
	 * Update the camera input states based on the provided input_class instance.
	 * This method updates the internal state of the camera's input handling.
	 * @param imputs A pointer to an input_class instance containing the current input states.
	 */
	void update_camera_inputs_states(input_class* imputs);

	/**
	 * Set the camera inputs structure.
	 * @param inputs A shared pointer to a CameraInput structure containing the input states.
	 */
	void set_camera_inputs(std::shared_ptr<CameraInput> inputs) { inputs_ = inputs; }

	/**
	 * Get the camera inputs structure.
	 * @return A shared pointer to the CameraInput structure containing the input states.
	 */
	std::shared_ptr<CameraInput> get_camera_inputs() { return inputs_; }

private:
	float position_x_, position_y_, position_z_;
	float rotation_x_, rotation_y_, rotation_z_;
	XMMATRIX view_matrix_;
	XMMATRIX reflection_view_matrix_;

	float camera_speed_;
	std::shared_ptr<CameraInput> inputs_;
	float camera_sensitivity_ = 0.1f;
};

#endif