#pragma once
/**
 * @file texture2d_atlas.h
 * @brief 纹理图集类定义
 */
#include "texture_atlas_types.h"
#include "texture/rw_texture2d.h"
#include <memory>
#include <vector>
#include <unordered_map>
#include <optional>

/**
 * @class texture2d_atlas
 * @brief 纹理图集类，管理单个大纹理上的多个子区域
 */
class texture2d_atlas {
public:
    //-------------- 构造和析构 --------------
    /**
     * @brief 构造函数
     * @param size 图集纹理大小
     * @param pixel_format 纹理像素格式
     * @param strategy 分配策略
     */
    texture2d_atlas(const Eigen::Vector2i& size, sg_pixel_format pixel_format,
                    allocation_strategy_t strategy = allocation_strategy_t::bin_packing);

    /**
     * @brief 析构函数
     */
    ~texture2d_atlas();

    //-------------- 区域分配 --------------
    /**
     * @brief 分配指定大小的纹理区域
     * @param size 要分配的区域大小
     * @return 分配的区域，失败返回std::nullopt
     */
    std::optional<rect_t<int32_t>> allocate(const Eigen::Vector2i& size);

    /**
     * @brief 分配区域并返回完整区域信息
     * @param size 要分配的区域大小
     * @return 分配的区域信息，失败返回std::nullopt
     */
    std::optional<atlas_region_t> allocate_region(const Eigen::Vector2i& size, const Eigen::Vector2i& padding = {0, 0});

    /**
     * @brief 释放之前分配的纹理区域
     * @param rect 要释放的区域
     * @return 是否成功释放
     */
    bool free(const rect_t<int32_t>& rect);

    /**
     * @brief 根据ID释放区域
     * @param region_id 要释放的区域ID
     * @return 是否成功释放
     */
    bool free_region(int region_id);

    //-------------- 纹理访问 --------------
    /**
     * @brief 获取底层纹理
     */
    auto get_texture() const { return texture_; }

    //-------------- 图集管理 --------------
    /**
     * @brief 调整图集大小
     * @note 会导致所有已分配区域失效
     */
    void resize(const Eigen::Vector2i& new_size);

    /**
     * @brief 清空所有分配
     */
    void clear();

    /**
     * @brief 更新指定区域的数据
     */
    void update_region(const void* data, size_t data_size, const rect_t<int32_t>& rect);

    //-------------- 状态查询 --------------
    /**
     * @brief 获取图集大小
     */
    Eigen::Vector2i get_size() const { return texture_->get_size(); }

    /**
     * @brief 获取剩余可用空间比例
     * @return 0.0-1.0之间的值
     */
    float get_free_space_ratio() const;

    /**
     * @brief 获取所有已分配区域
     * @return 所有已分配区域的列表
     */
    std::vector<atlas_region_t> get_allocated_regions() const;

    /**
     * @brief 计算区域的UV坐标
     * @param rect 像素坐标中的矩形
     * @return UV坐标中的矩形
     */
    rect_uv calculate_uv_rect(const rect_t<int32_t>& rect) const;

private:
    /**
     * @brief 创建分配器
     * @param strategy 分配策略
     * @param size 区域大小
     * @return 创建的分配器指针
     */
    std::unique_ptr<atlas_allocator> create_allocator(allocation_strategy_t strategy,
                                                     const Eigen::Vector2i& size);

    std::shared_ptr<rw_texture2d> texture_;                              ///< 底层纹理
    std::unique_ptr<atlas_allocator> allocator_;        ///< 区域分配器
    std::unordered_map<int, atlas_region_t> allocated_regions_; ///< 存储已分配区域
    int next_region_id_ = 1;                           ///< 区域ID生成器
};
