/**
 * @file texture2d_atlas.cpp
 * @brief 纹理图集类实现
 */
#include "texture2d_atlas.h"
#include "bin_packing_allocator.h"
#include "grid_allocator.h"
#include "skyline_allocator.h"
#include "texture/texture_map_utils.h" // 从知识库引用
#include <stdexcept>

#include "font/font_type.h"

texture2d_atlas::texture2d_atlas(const Eigen::Vector2i& size, sg_pixel_format pixel_format,
                                 allocation_strategy_t strategy)
{
	texture_ = std::make_shared<rw_texture2d>();
    // 创建底层纹理
    rw_texture2d_data tex_data;
    tex_data.size = size;
    tex_data.pixel_format = pixel_format;
    tex_data.data_ptr = nullptr;  // 初始为空
    texture_->create(tex_data);

    // 创建分配器
    allocator_ = create_allocator(strategy, size);
}

texture2d_atlas::~texture2d_atlas() = default;

std::optional<rect_t<int32_t>> texture2d_atlas::allocate(const Eigen::Vector2i& size) {
    auto region_opt = allocate_region(size);
    if (region_opt) {
        return region_opt->rect;
    }
    return std::nullopt;
}

std::optional<atlas_region_t> texture2d_atlas::allocate_region(const Eigen::Vector2i& size, const Eigen::Vector2i& padding) {
	if (!allocator_) {
		return std::nullopt;
	}

	// 计算包含padding的总尺寸
	const Eigen::Vector2i& padded_size = size + padding * 2; // 每边加上padding

	// 使用分配器分配包含padding的区域
	const auto& rect_opt = allocator_->allocate(padded_size);
	if (!rect_opt) {
		return std::nullopt; // 分配失败
	}

	// 分配成功，创建区域信息
	const int region_id = next_region_id_++;

	// 获取分配的带padding的矩形
	const auto& padded_rect = *rect_opt;

	const Eigen::Vector2i& content_position = padded_rect.top_left() + padding;

	// 计算内部有效区域（不含padding）
	rect_t<int32_t> content_rect{ content_position, size };

	// 创建region对象，使用内容区域的UV坐标
	atlas_region_t region(region_id, content_rect, texture_, calculate_uv_rect(content_rect));

	// 存储区域信息
	allocated_regions_[region.id] = region;

	return region;
}

bool texture2d_atlas::free(const rect_t<int32_t>& rect) {
    // 查找与此矩形对应的区域ID
    for (const auto& [id, region] : allocated_regions_) {
        if (region.rect == rect) {
            return free_region(id);
        }
    }
    return false;
}

bool texture2d_atlas::free_region(int region_id) {
    auto it = allocated_regions_.find(region_id);
    if (it == allocated_regions_.end()) {
        return false; // 区域不存在
    }

    // 使用分配器释放区域
    bool result = allocator_->free(it->second.rect);
    if (result) {
        // 从已分配列表中移除
        allocated_regions_.erase(it);
    }

    return result;
}

void texture2d_atlas::resize(const Eigen::Vector2i& new_size) {
    texture_->resize(new_size);
    if (allocator_) {
        allocator_->resize(new_size);
    }
    // 调整大小会导致所有已分配区域失效
    allocated_regions_.clear();
}

void texture2d_atlas::clear() {
    if (allocator_) {
        allocator_->reset();
    }
    allocated_regions_.clear();
}

void texture2d_atlas::update_region(const void* data, size_t data_size, const rect_t<int32_t>& rect) {
    if (!data || data_size == 0) {
        return;
    }

    // 确保区域在纹理范围内
    if (rect.left() < 0 || rect.top() < 0 ||
        rect.right() > texture_->get_size().x() ||
        rect.bottom() > texture_->get_size().y()) {
        return;
    }

    // 更新纹理区域
    texture_->sub_update({ data, data_size }, rect);

    // 使用texture_map_utils更新区域
    // texture_map_utils::write_region(*map.get(), data, rect, texture_->get_bytes_per_pixel());
}

float texture2d_atlas::get_free_space_ratio() const {
    if (!allocator_) {
        return 0.0f;
    }

    int total = allocator_->total_area();
    if (total == 0) {
        return 0.0f;
    }

    return 1.0f - static_cast<float>(allocator_->allocated_area()) / total;
}

std::vector<atlas_region_t> texture2d_atlas::get_allocated_regions() const {
    std::vector<atlas_region_t> result;
    result.reserve(allocated_regions_.size());

    for (const auto& [id, region] : allocated_regions_) {
        result.push_back(region);
    }

    return result;
}

rect_uv texture2d_atlas::calculate_uv_rect(const rect_t<int32_t>& rect) const {
    // 计算UV坐标 (归一化到0-1范围)
    const Eigen::Vector2i& texture_size = texture_->get_size();
    const float left = static_cast<float>(rect.left()) / texture_size.x();
    const float top = static_cast<float>(rect.top()) / texture_size.y();
	const float right = static_cast<float>(rect.right()) / texture_size.x();
	const float bottom = static_cast<float>(rect.bottom()) / texture_size.y();

	const Eigen::Vector2f left_top(left, top);
	const Eigen::Vector2f left_bottom(left, bottom);
	const Eigen::Vector2f right_top(right, top);
	const Eigen::Vector2f right_bottom(right, bottom);

	return { left_top, right_top, left_bottom, right_bottom };
}

std::unique_ptr<atlas_allocator> texture2d_atlas::create_allocator(allocation_strategy_t strategy,
                                                                 const Eigen::Vector2i& size) {
    switch (strategy) {
        case allocation_strategy_t::bin_packing:
            return std::make_unique<bin_packing_allocator>(size);

        case allocation_strategy_t::grid:
            // 默认使用16x16的网格
            return std::make_unique<grid_allocator>(size, Eigen::Vector2i(16, 16));

        case allocation_strategy_t::skyline:
            return std::make_unique<skyline_allocator>(size);

        default:
            throw std::invalid_argument("不支持的分配策略");
    }
}
