#pragma once
#include <spdlog/spdlog.h>

#include "core/pipeline/pipeline.h"
#include "core/pipeline/rect_pipeline.h"
#include "core/pipeline/rounded_rect_pipeline.h"

class renderer_texture;

struct rect_radius {
    rect_radius(float radius) : top_left(radius), top_right(radius), bottom_left(radius), bottom_right(radius) {}
    rect_radius(float top, float bottom) : top_left(top), top_right(top), bottom_left(bottom), bottom_right(bottom) {}
    rect_radius(float top_left, float top_right, float bottom_left, float bottom_right) : top_left(top_left), top_right(top_right), bottom_left(bottom_left), bottom_right(bottom_right) {}

    float top_left;
    float top_right;
    float bottom_left;
    float bottom_right;

    operator Eigen::Vector4f() const {
        return { top_left, top_right, bottom_left, bottom_right };
    }
};

class renderer_context {
public:
    void init();
    /**
     * 绘制一个实心矩形
     * @param in_pos 当前控件坐标系的位置
     * @param in_size 绘制的大小(受控件缩放影响)
     * @param in_color 绘制的颜色
     */
    void draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color);

    /**
     * 绘制一个实心圆角矩形
     * @param in_pos 当前控件坐标系的位置
     * @param in_size 绘制的大小(受控件缩放影响)
     * @param in_color 绘制的颜色
     * @param in_angle
     * @param in_radius 圆角半径(像素)
     */
    void draw_rounded_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle, const rect_radius& in_radius);

    /**
     * 绘制一条线
     * @param in_pos_p1 点1
     * @param in_pos_p2 点2
     * @param in_color 线颜色
     * @param in_thickness 线宽度(像素), 当宽度为0时, 按照最小线宽度绘制
     */
    void draw_line(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, const linear_color& in_color, float in_thickness);

    /**
     * 绘制一个纹理
     * @param in_pos 当前控件坐标系的位置
     * @param in_size 绘制的大小(受控件缩放影响)
     * @param in_texture 纹理
     */
    void draw_texture(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, renderer_texture* in_texture, const linear_color& in_color = linear_color::white);

    void draw_string(const Eigen::Vector2f& in_pos, const std::u32string& in_str, float in_height, const linear_color& in_color = linear_color::white);

    void clear() {
        vertices.clear();
        triangles.clear();
    }

    [[nodiscard]] const std::vector<aorii_vertex>& get_vertices() const {
        return vertices;
    }
    [[nodiscard]] const std::vector<aorii_triangle>& get_triangles() const {
        return triangles;
    }
    void flush() {
        if (vertices.empty() || triangles.empty()) return;
        if (current_pipeline) {
            current_pipeline->set_triangle(vertices, triangles);
            current_pipeline->draw(triangles.size() * 3);
        }
        clear();
    }
    void set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size);

protected:
    void switch_pipeline(pipeline* in_pipeline) {
#if DEBUG
        if (!in_pipeline)
            spdlog::critical("尝试切换到空管线");
#endif
        if (current_pipeline != in_pipeline && in_pipeline) {
            flush();
            current_pipeline = in_pipeline;
            current_pipeline->use();
        }
    }

    void to_rect_pipeline();
    void to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const rect_radius& in_radius);
    void to_texture_pipeline(renderer_texture* in_texture);
    void to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness);
    void to_text_pipeline(const linear_color& in_color);
private:
    std::vector<aorii_vertex> vertices;
    std::vector<aorii_triangle> triangles;

    pipeline* current_pipeline = nullptr;
    Eigen::Matrix4f projection_matrix;
    Eigen::Vector2i framebuffer_size;
private:
    void make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color, float in_angle = 0, const aorii_vertex_param& in_param = {});
    void rotate_vertex(float in_angle, const Eigen::Vector2f& in_center);
};
