#pragma once
/**
 * @file render_elements.h
 * @brief 定义用于批处理渲染的基础元素和类
 *
 * 本文件定义了render_elements类和相关的结构体，用于高效地批处理渲染UI元素。
 * 包括批次键、批次数据、几何数据类型和渲染方法。
 */

#include "geometry/geometry.h"
#include "geometry/layout_transform.h"
#include "sokol_gfx.h"
#include "color.h"
#include "texture_sampler.h"
#include "font/font_type.h"
#include "misc/mirage_type.h"

/**
 * @enum draw_effect
 * @brief 定义渲染效果类型
 *
 * 用于指定特殊的渲染效果。当前为空，但可以在将来扩展。
 */
enum class draw_effect {
};

/**
 * @struct batch_key
 * @brief 用于标识渲染批次的键
 *
 * 包含影响渲染状态的元素，用于确定是否可以将绘制命令批处理在一起。
 */
struct batch_key {
    /** 渲染管线 */
    sg_pipeline pipeline{};

    /** 使用的纹理 */
    sg_image image{};

	/** 使用的采样器 */
	sg_sampler sampler{};

    // 可选：添加其他影响状态的元素，如着色器、混合模式等

    /**
     * @brief 相等比较运算符
     * @param other 要比较的另一个批次键
     * @return 如果两个批次键相等则返回true
     */
    bool operator==(const batch_key& other) const {
	    return pipeline.id == other.pipeline.id &&
	           image.id == other.image.id &&
	           sampler.id == other.sampler.id;
    }

    /**
     * @brief 小于比较运算符
     * @param other 要比较的另一个批次键
     * @return 如果当前批次键小于另一个则返回true
     */
	bool operator<(const batch_key& other) const {
    	if (pipeline.id != other.pipeline.id)
    		return pipeline.id < other.pipeline.id;
    	if (image.id != other.image.id)
    		return image.id < other.image.id;
    	return sampler.id < other.sampler.id;  // 缺少这一行
    }
};

/**
 * @struct draw_batch
 * @brief 表示一个绘制批次
 *
 * 存储批次的渲染状态和其在顶点/索引缓冲区中的范围。
 */
struct draw_batch {
    /** 批次的渲染状态键 */
    batch_key key;

    /** 批次在顶点缓冲区中的起始索引 */
    uint32_t vertex_start = 0;

    /** 批次包含的顶点数量 */
    uint32_t vertex_count = 0;

    /** 批次在索引缓冲区中的起始索引 */
    uint32_t index_start = 0;

    /** 批次包含的索引数量 */
    uint32_t index_count = 0;
};

/**
 * @class render_elements
 * @brief 管理渲染资源和批处理渲染操作
 *
 * 提供API用于高效地批处理渲染UI元素，管理GPU资源，
 * 并处理渲染状态和变换。
 */
class render_elements {
public:
    //-------------- 生命周期和初始化 --------------

    /**
     * @brief 默认构造函数
     */
    render_elements() = default;

    /**
     * @brief 析构函数
     *
     * 释放所有分配的GPU资源。
     */
    ~render_elements();

    /**
     * @brief 创建渲染所需的GPU资源
     *
     * 初始化顶点和索引缓冲区。
     */
    void create_resources();

    /**
     * @brief 加载UI渲染特定的管线
     *
     * 创建用于UI渲染的着色器管线，如标准矩形和圆角矩形。
     */
    void load_mirage_pipelines();

    /**
     * @brief 初始化窗口大小
     * @param in_size 窗口大小
     *
     * 设置初始窗口大小并创建相应的投影矩阵。
     */
    void init_window_size(const Eigen::Vector2i& in_size);

    //-------------- 帧控制 --------------

    /**
     * @brief 开始新一帧的渲染
     *
     * 重置批次状态并准备新一帧的渲染。
     */
    void begin_frame();

    /**
     * @brief 结束当前帧并提交所有批次
     *
     * 将所有待处理的批次刷新到GPU并执行绘制。
     */
    void end_frame();

    //-------------- 渲染状态设置 --------------

    /**
     * @brief 设置当前渲染管线
     * @param pipeline 要使用的管线
     */
    void set_pipeline(sg_pipeline pipeline);

    /**
     * @brief 设置当前纹理
     * @param image 要使用的纹理
     */
    void set_texture(sg_image image);

	/**
	 * @brief 设置当前采样器
	 * @param sampler 采样器
	 */
	void set_sampler(sg_sampler sampler);

    //-------------- 变换和投影 --------------

    /**
     * @brief 创建投影矩阵
     * @param in_size 视口大小
     * @return 正交投影矩阵
     */
    static Eigen::Matrix4f create_projection_matrix(const Eigen::Vector2i& in_size);

    /**
     * @brief 更新投影矩阵
     * @param in_size 新的视口大小
     *
     * 当窗口大小变化时更新投影矩阵。
     */
    void update_projection_matrix(const Eigen::Vector2i& in_size);

    //-------------- 绘制方法 --------------

    /**
     * @brief 添加矩形到当前批次
     * @param in_pos 矩形位置
     * @param in_size 矩形大小
     * @param in_color 矩形颜色（每个角点可以不同）
     * @param in_geometry 关联的几何信息
     * @param in_param_a 顶点参数A（用于着色器）
     * @param in_param_b 顶点参数B（用于着色器）
     * @param in_param_c 顶点参数C（用于着色器）
     * @param in_uv 纹理坐标（每个角点可以不同）
     * @param in_rotation_radians 旋转角度（弧度）
     * @param in_pivot 旋转和缩放的枢轴点（0到1范围）
     * @param in_scale 缩放因子
     */
    void make_rect(const Eigen::Vector2f&      in_pos,
                  const Eigen::Vector2f&       in_size,
                  const rect_color&            in_color,
                  const geometry_t&            in_geometry,
                  const mirage_vertex_param_t& in_param_a          = {},
                  const mirage_vertex_param_t& in_param_b          = {},
                  const mirage_vertex_param_t& in_param_c          = {},
                  const rect_uv&               in_uv               = {},
                  float                        in_rotation_radians = 0.0f,
                  const Eigen::Vector2f&       in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                  const Eigen::Vector2f&       in_scale            = Eigen::Vector2f(1.f, 1.f));

    /**
     * @brief 添加圆角矩形到当前批次
     * @param in_pos 矩形位置
     * @param in_size 矩形大小
     * @param in_geometry 关联的几何信息
     * @param in_color 矩形颜色（每个角点可以不同）
     * @param in_round 每个角的圆角半径
     * @param in_rotation_radians 旋转角度（弧度）
     * @param in_pivot 旋转和缩放的枢轴点（0到1范围）
     * @param in_uv 纹理坐标（每个角点可以不同）
     * @param in_scale 缩放因子
     */
    void make_rounded_rect(const Eigen::Vector2f& in_pos,
                          const Eigen::Vector2f&  in_size,
                          const geometry_t&       in_geometry,
                          const rect_color&       in_color            = { { 1, 1, 1, 1 } },
                          const rect_round&       in_round            = {},
                          float                   in_rotation_radians = 0.0f,
                          const Eigen::Vector2f&  in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                          const rect_uv&          in_uv               = {},
                          const Eigen::Vector2f&  in_scale            = Eigen::Vector2f(1.f, 1.f));

    void make_image(const Eigen::Vector2f& in_pos,
                    const Eigen::Vector2f& in_size,
                    const geometry_t&      in_geometry,
                    const sg_image&        in_image,
                    sampler_type           in_sampler_type,
                    const rect_color&    in_color            = { { 1, 1, 1, 1 } },
                    const rect_uv&         in_uv               = {},
                    float                  in_rotation_radians = 0.0f,
                    const Eigen::Vector2f& in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                    const Eigen::Vector2f& in_scale            = Eigen::Vector2f(1.f, 1.f));

    void make_image(const Eigen::Vector2f& in_pos,
                    const Eigen::Vector2f& in_size,
                    const geometry_t&      in_geometry,
                    const sg_image&        in_image,
                    const std::shared_ptr<texture_sampler>& in_sampler,
                    const rect_color&    in_color            = { { 1, 1, 1, 1 } },
                    const rect_uv&         in_uv               = {},
                    float                  in_rotation_radians = 0.0f,
                    const Eigen::Vector2f& in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                    const Eigen::Vector2f& in_scale            = Eigen::Vector2f(1.f, 1.f));

    void make_text(const text_layout_t& in_layout,
                   const Eigen::Vector2f& in_pos,
                   const Eigen::Vector2f& in_size,
                   const geometry_t&      in_geometry,
                   const rect_color&    in_color            = { { 1, 1, 1, 1 } },
                   float                  in_rotation_radians = 0.0f,
                   const Eigen::Vector2f& in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                   const Eigen::Vector2f& in_scale            = Eigen::Vector2f(1.f, 1.f));

    void make_wireframe(const Eigen::Vector2f& in_pos,
                        const Eigen::Vector2f& in_size,
                        const geometry_t&      in_geometry,
                        float in_line_width,
                        const rect_color&      in_color            = { { 1, 1, 1, 1 } },
                        float                  in_rotation_radians = 0.0f,
                        const Eigen::Vector2f& in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                        const Eigen::Vector2f& in_scale            = Eigen::Vector2f(1.f, 1.f));

    void make_line(const Eigen::Vector2f& in_start,
                   const Eigen::Vector2f& in_end,
                   const geometry_t&      in_geometry,
                   float                  in_thickness,
                   const rect_color&      in_color            = { { 1, 1, 1, 1 } },
                   float                  in_rotation_radians = 0.0f,
                   const Eigen::Vector2f& in_pivot            = Eigen::Vector2f(0.5f, 0.5f),
                   const Eigen::Vector2f& in_scale            = Eigen::Vector2f(1.f, 1.f));

	//-------------- 统计信息 --------------

	/**
	 * @brief 获取绘制调用次数
	 * @return 绘制调用次数
	 */
	[[nodiscard]] uint32_t get_draw_call_count() const { return draw_call_count_; }

	/**
	 * @brief 获取总三角形数量
	 * @return 总三角形数量
	 */
	[[nodiscard]] uint32_t get_total_triangles() const { return total_triangles_; }

	//-------------- 禁用拷贝和赋值 --------------

	render_elements(const render_elements&) = delete;
	render_elements& operator=(const render_elements&) = delete;

	render_elements(render_elements&&)            = delete;
    render_elements& operator=(render_elements&&) = delete;
private:
    //-------------- 内部辅助方法 --------------

    /**
     * @brief 根据顶点和索引数据创建一个矩形
     * @param in_pos 矩形位置
     * @param in_size 矩形大小
     * @param in_color 矩形颜色
     * @param in_param_a 顶点参数A
     * @param in_param_b 顶点参数B
     * @param in_param_c 顶点参数C
     * @param in_uv 纹理坐标
     * @param in_rotation_radians 旋转角度
     * @param in_scale 缩放因子
     * @param in_pivot 旋转和缩放的枢轴点
     */
    void add_rect_to_batch(const Eigen::Vector2f&       in_pos,
                           const Eigen::Vector2f&       in_size,
                           const rect_color&            in_color,
                           const mirage_vertex_param_t& in_param_a,
                           const mirage_vertex_param_t& in_param_b,
                           const mirage_vertex_param_t& in_param_c,
                           const rect_uv&               in_uv,
                           float                        in_rotation_radians,
                           const Eigen::Vector2f&       in_scale,
                           const Eigen::Vector2f&       in_pivot);

    /**
     * @brief 确保当前批次与给定的渲染状态兼容
     * @param key 渲染状态键
     *
     * 如果当前批次与新的渲染状态不兼容，则创建新批次。
     */
    void ensure_batch_compatibility(const batch_key& key);

    /**
     * @brief 将当前批次数据上传到GPU
     *
     * 将所有批次的顶点和索引数据上传到GPU并提交绘制命令。
     */
    void flush_batches();

    /**
     * @brief 确保缓冲区容量足够
     * @param vertex_count 需要的顶点数量
     * @param index_count 需要的索引数量
     *
     * 如果当前缓冲区容量不足，则重新分配更大的缓冲区。
     */
    void ensure_buffer_capacity(uint32_t vertex_count, uint32_t index_count);

    //-------------- 成员变量 --------------

    /** 当前渲染状态键 */
    batch_key current_key_{};

    /** 当前批次索引 */
    int32_t current_batch_index_ = -1;

    /** 所有待渲染的批次 */
    std::vector<draw_batch> batches_;

    /** 顶点数据 */
    std::vector<mirage_vertex_t> vertices_;

    /** 索引数据 */
    std::vector<uint32_t> indices_;

    /** GPU顶点缓冲区 */
    sg_buffer vertex_buffer_{};

    /** GPU索引缓冲区 */
    sg_buffer index_buffer_{};

    /** 顶点缓冲区容量 */
    uint32_t vertex_buffer_capacity_ = 0;

    /** 索引缓冲区容量 */
    uint32_t index_buffer_capacity_ = 0;

    /** 绘制调用计数（统计） */
    uint32_t draw_call_count_ = 0;

    /** 总三角形数量（统计） */
    uint32_t total_triangles_ = 0;

    /** 投影矩阵 */
    Eigen::Matrix4f projection_matrix_{ Eigen::Matrix4f::Identity() };

    /** 窗口大小 */
    Eigen::Vector2i window_size_{ 0, 0 };

    /** 圆角矩形渲染管线 */
    sg_pipeline rounded_rect_pipeline_{};

	/** 图片渲染管线 */
	sg_pipeline image_pipeline_{};

	/** 文本渲染管线 */
	sg_pipeline text_pipeline_{};

	/** 线框渲染管线 */
	sg_pipeline wireframe_pipeline_{};

	/** 线条渲染管线 */
	sg_pipeline line_pipeline_{};
};
