#pragma once

#include <glm/glm.hpp>
#include <glm/mat3x3.hpp>
#include <vector>
#include <string>

namespace Vivid2D::util {

    /**
     * @class BoundingBox
     * @brief 一个二维轴对齐边界框 (AABB)，用于表示和管理对象边界。
     * 支持变换、合并、交集测试和其他操作。
     */
    class VIVID_2D_MYDLL_API BoundingBox {
    public:
        // ==================== 构造函数 ====================

        /**
         * @brief 创建一个未初始化、无效的边界框。
         */
        BoundingBox();

        /**
         * @brief 从最小和最大坐标创建边界框。
         */
        BoundingBox(float minX, float minY, float maxX, float maxY);

        /**
         * @brief 从两个角点创建边界框。
         */
        BoundingBox(const glm::vec2& point1, const glm::vec2& point2);

        /**
         * @brief 复制构造函数。
         */
        BoundingBox(const BoundingBox& other);

        /**
         * @brief 从一组点创建边界框。
         */
        explicit BoundingBox(const std::vector<glm::vec2>& points);

        /**
         * @brief 从一个顶点数组 [x0, y0, x1, y1, ...] 创建边界框。
         */
        explicit BoundingBox(const std::vector<float>& vertices);


        // ==================== 设置方法 ====================

        /**
         * @brief 将边界框重置为无效状态。
         */
        void reset();

        /**
         * @brief 设置边界值。
         */
        void set(float minX, float minY, float maxX, float maxY);

        /**
         * @brief 从两个点设置边界。
         */
        void set(const glm::vec2& point1, const glm::vec2& point2);

        /**
         * @brief 从另一个边界框设置边界。
         */
        void set(const BoundingBox& other);

        /**
         * @brief 从一组点设置边界。
         */
        void set(const std::vector<glm::vec2>& points);

        /**
         * @brief 从一个顶点数组 [x0, y0, x1, y1, ...] 设置边界。
         */
        void set(const std::vector<float>& vertices);


        // ==================== 扩展方法 ====================

        /**
         * @brief 扩展边界框以包含一个点。
         */
        void expand(float x, float y);
        void expand(const glm::vec2& point);

        /**
         * @brief 扩展边界框以包含另一个边界框。
         */
        void expand(const BoundingBox& other);

        /**
         * @brief 扩展边界框以包含一组点。
         */
        void expand(const std::vector<glm::vec2>& points);

        /**
         * @brief 扩展边界框以包含一个顶点数组。
         */
        void expand(const std::vector<float>& vertices);


        // ==================== 变换方法 (返回新的 BoundingBox) ====================

        /**
         * @brief 应用矩阵变换并返回新的 AABB。
         */
        BoundingBox transform(const glm::mat3& matrix) const;

        /**
         * @brief 应用平移并返回新的 BoundingBox。
         */
        BoundingBox translate(float dx, float dy) const;
        BoundingBox translate(const glm::vec2& translation) const;

        /**
         * @brief 应用缩放并返回新的 BoundingBox。
         */
        BoundingBox scale(float sx, float sy) const;
        BoundingBox scale(float scale) const;
        BoundingBox scale(const glm::vec2& scale) const;


        // ==================== 几何计算 ====================

        /**
         * @brief 获取边界框的四个角点。
         */
        std::vector<glm::vec2> getCorners() const;

        /**
         * @brief 获取边界框的中心点。
         */
        glm::vec2 getCenter() const;

        /**
         * @brief 获取边界框的尺寸 (宽度, 高度)。
         */
        glm::vec2 getSize() const;

        /**
         * @brief 获取边界框的半尺寸 (范围/Extents)。
         */
        glm::vec2 getHalfSize() const;

        float getArea() const;
        float getPerimeter() const;


        // ==================== 交集测试 ====================

        /**
         * @brief 检查边界框是否包含一个点。
         */
        bool contains(float x, float y) const;
        bool contains(const glm::vec2& point) const;

        /**
         * @brief 检查此边界框是否完全包含另一个边界框。
         */
        bool contains(const BoundingBox& other) const;

        /**
         * @brief 检查此边界框是否与另一个边界框相交。
         */
        bool intersects(const BoundingBox& other) const;

        /**
         * @brief 返回此边界框与另一个边界框的交集。
         */
        BoundingBox intersection(const BoundingBox& other) const;

        /**
         * @brief 返回此边界框与另一个边界框的并集。
         */
        BoundingBox getUnion(const BoundingBox& other) const;


        // ==================== 实用方法 (返回新的 BoundingBox) ====================

        /**
         * @brief 在所有方向上将边界框扩大一个固定量。
         */
        BoundingBox inflate(float amount) const;
        BoundingBox inflate(float dx, float dy) const;

        /**
         * @brief 在所有方向上将边界框缩小一个固定量。
         */
        BoundingBox deflate(float amount) const;
        BoundingBox deflate(float dx, float dy) const;

        /**
         * @brief 返回一个对齐到网格的新边界框。
         */
        BoundingBox alignToGrid(float gridSize) const;

        /**
         * @brief 计算到某个点的最短距离。
         */
        float distanceTo(float x, float y) const;
        float distanceTo(const glm::vec2& point) const;


        // ==================== 获取器 (Getters) ====================

        float getMinX() const { return m_Min.x; }
        float getMinY() const { return m_Min.y; }
        float getMaxX() const { return m_Max.x; }
        float getMaxY() const { return m_Max.y; }
        const glm::vec2& getMin() const { return m_Min; }
        const glm::vec2& getMax() const { return m_Max; }

        float getWidth() const;
        float getHeight() const;

        /**
         * @brief 检查边界框是否有效 (m_Min.x <= m_Max.x 且 m_Min.y <= m_Max.y)。
         */
        bool isValid() const { return m_IsValid; }


        // ==================== 对象方法 ====================

        /**
         * @brief 创建边界框的深拷贝。
         */
        BoundingBox copy() const;

        /**
         * @brief 返回边界框的字符串表示。
         */
        std::string toString() const;

        /**
         * @brief 重载相等运算符。
         */
        bool operator==(const BoundingBox& other) const;

        /**
         * @brief 重载不等运算符。
         */
        bool operator!=(const BoundingBox& other) const;

        // ==================== 静态工厂方法 ====================

        /**
         * @brief 从一组点创建并返回一个边界框。
         */
        static BoundingBox fromPoints(const std::vector<glm::vec2>& points);

        /**
         * @brief 从一个顶点数组创建并返回一个边界框。
         */
        static BoundingBox fromVertices(const std::vector<float>& vertices);

        /**
         * @brief 合并两个边界框并返回它们的并集。
         */
        static BoundingBox merge(const BoundingBox& box1, const BoundingBox& box2);

        /**
         * @brief 合并一组边界框并返回它们的并集。
         */
        static BoundingBox mergeAll(const std::vector<BoundingBox>& boxes);

    private:
        glm::vec2 m_Min; ///< 边界框的最小坐标点 (x, y)
        glm::vec2 m_Max; ///< 边界框的最大坐标点 (x, y)
        bool m_IsValid;  ///< 指示边界框是否有效
    };

} // namespace Vivid2D::util