#pragma once

#include "Types.hpp"

namespace TSE
{
    class Vector3;
    class Vector4;

    class Quaternion
    {
        public:
        #pragma region members
        float x = 0, y = 0, z = 0, w = 1;
        #pragma endregion members

        #pragma region ctor
        /// @brief constructs a default Quaternion
        Quaternion();
        /// @brief constructs a Quaternion with given values
        /// @param _x the x component
        /// @param _y the y component
        /// @param _z the z component
        /// @param _w the w component
        Quaternion(float _x, float _y, float _z, float _w);
        /// @brief copy constructor
        /// @param other the quaternion to be copied
        Quaternion(const Quaternion& other);
        /// @brief conversion constructor
        /// @param other the vector4 to be converted
        Quaternion(const Vector4& other);
        #pragma endregion ctor

        #pragma region methods
        /// @brief converts the Quaternion to a Vector3 with yaw, pitch, and roll
        /// @return the euler angles
        Vector3 ToEulerAngles() const;
        /// @brief rotates a point with the quaternion
        /// @param v the point to rotate
        /// @return the rotated point
        Vector3 Rotate(const Vector3& v) const;
        /// @brief normalizes the current quaternion
        void Normalize();

        #pragma region static
        /// @brief gives you a quaternion based on an angle axis input
        /// @param angleRad the angle in radiants
        /// @param axis the axis to ratate around
        /// @return the resulting quaternion
        static Quaternion FromAngleAxis(float angleRad, const Vector3& axis);
        /// @brief gives you a quaternion based on euler angles
        /// @param euler the euler angles
        /// @return the resulting quaternion
        static Quaternion FromEulerAngles(const Vector3& euler);
        /// @brief converts a Quaternion to a Vector3 with yaw, pitch, and roll
        /// @param q the quaternion to convert
        /// @return the euler angles
        static Vector3 ToEulerAngles(const Quaternion& q);
        #pragma endregion static

        #pragma region operators
        Quaternion operator*(const Quaternion& other) const;
        Quaternion operator*=(const Quaternion& other);
        bool operator==(const Quaternion& other) const;
        bool operator!=(const Quaternion& other) const;
        #pragma endregion operators
        #pragma endregion methods
    };
} // namespace TSE
