//
// Created by sebastian on 04.08.26.
//

#ifndef COLORRACE_AABB_H
#define COLORRACE_AABB_H
#include <optional>

#include "Ray.h"
#include "glm/fwd.hpp"
#include "glm/vec3.hpp"


namespace engine {
    class AABB {
    public:
        AABB() = default;
        AABB(const glm::vec3& min, const glm::vec3& max) : m_min(min), m_max(max) {}

        static AABB fromCenterAndHalfExtent(const glm::vec3& center, const glm::vec3& halfExtent) {
            return AABB(center - halfExtent, center + halfExtent);
        }

        const glm::vec3& getMin() const { return m_min; }
        const glm::vec3& getMax() const { return m_max; }

        glm::vec3 getCenter() const { return (m_min + m_max) * 0.5f; }
        glm::vec3 getHalfExtent() const { return (m_max - m_min) * 0.5f; }
        glm::vec3 getSize() const { return m_max - m_min; }

        void expandToInclude(const glm::vec3& point);
        void expandToInclude(const AABB& other);

        AABB transformed(const glm::mat4& transform) const;

        [[nodiscard]] bool contains(const glm::vec3 &point) const {
            return point.x >= m_min.x && point.x <= m_max.x
            && point.y >= m_min.y && point.y <= m_max.y
            && point.z >= m_min.z && point.z <= m_max.z;
        }

        [[nodiscard]] bool intersects(const AABB &other) const {
            return m_min.x <= other.m_max.x && m_max.x >= other.m_min.x
            && m_min.y <= other.m_max.y && m_max.y >= other.m_min.y
            && m_min.z <= other.m_max.z && m_max.z >= other.m_min.z;
        }

        std::optional<RayHit> intersects(const Ray &ray, float maxDistance = std::numeric_limits<float>::max()) const;

    private:
        glm::vec3 m_min{0.f};
        glm::vec3 m_max{0.f};
    };
}


#endif //COLORRACE_AABB_H
