#include "renderer_context.h"

#include "renderer.h"
#include "renderer_text.h"
#include "backend/dx/dx_renderer.h"

aorii_text* text = nullptr;
void renderer_context::init() {
    text = new aorii_text();
    // D:\Projects\aorii\JetBrainsMono-Regular.ttf
    text->initialize(LR"(HarmonyOS_Sans_SC_Regular.ttf)");
    text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
    // text->precache_common_characters();
}

void renderer_context::draw_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color& in_color) {
    to_rect_pipeline();
    make_rect(in_pos, in_size, in_color);
}

void renderer_context::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) {
    to_rounded_rect_pipeline(in_pos, in_size, in_radius);
    // in_angle传入的是角度, 需要转换为弧度
#define M_PI 3.14159265358979323846
    in_angle = in_angle * M_PI / 180;

    make_rect(in_pos, in_size, in_color, in_angle);
    // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批
    flush();
}

void renderer_context::draw_line(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, const linear_color& in_color, float in_thickness) {

}

void renderer_context::draw_texture(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size,
                                    renderer_texture* in_texture, const linear_color& in_color) {
    to_texture_pipeline(in_texture);
    make_rect(in_pos, in_size, in_color);
    // 立刻绘制并重置管线, 因为下一个绘制命令的参数可能不同, 所以无法合批
    flush();
}

void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::u32string& in_str, float in_height, const linear_color& in_color) {
    to_text_pipeline(in_color);

    const auto& measure = text->measure_text(in_str, in_height);

    for (const auto& mch: measure) {
        const auto info = mch.item;
        if (!info)
            continue;
        const Eigen::Vector2f pos = mch.offset + in_pos;
        const Eigen::Vector2f size = Eigen::Vector2f{ info->get_width(), info->get_height() } * mch.size_scale;

        aorii_vertex_param param{};
        param.param_a1 = info->tex_u;
        param.param_a2 = info->tex_v;
        param.param_a3 = info->tex_z;
        param.param_b1 = info->u_size;
        param.param_b2 = info->v_size;

        make_rect(pos, size, in_color, 0, param);
    }
}

void renderer_context::set_projection_matrix(const Eigen::Matrix4f& in_matrix, const Eigen::Vector2i& in_framebuffer_size) {
    projection_matrix = in_matrix;
    framebuffer_size = in_framebuffer_size;

    // 更新默认管线的投影矩阵
    const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
    rect_p->set_param({ in_matrix });
    // 更新纹理管线的投影矩阵
    const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
    texture_p->set_param({ in_matrix });

    // 圆角矩形管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
    // 线段管线的投影矩阵不需要更新, 因为它在每次绘制时都会更新
}

void renderer_context::to_rect_pipeline() {
    const auto rect_p = aorii::get_renderer<dx_renderer>()->get_rect_pipeline();
    switch_pipeline(rect_p);
}

void renderer_context::to_rounded_rect_pipeline(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const rect_radius& in_radius) {
    const auto rounded_rect_p = aorii::get_renderer<dx_renderer>()->get_rounded_rect_pipeline();
    switch_pipeline(rounded_rect_p);

    rounded_rect_pipeline::param param;
    param.projection_matrix = projection_matrix;
    param.size = in_size;
    param.pos = in_pos;
    param.radius = in_radius;
    rounded_rect_p->set_param(param);
}

void renderer_context::to_texture_pipeline(renderer_texture* in_texture) {
    const auto texture_p = aorii::get_renderer<dx_renderer>()->get_texture_pipeline();
    switch_pipeline(texture_p);
    texture_p->set_texture(in_texture);
}

void renderer_context::to_segment_pipeline(const Eigen::Vector2f& in_pos_p1, const Eigen::Vector2f& in_pos_p2, float in_thickness) {
    const auto segment_p = aorii::get_renderer<dx_renderer>()->get_segment_pipeline();
    switch_pipeline(segment_p);

    segment_pipeline::param param;
    param.projection_matrix = projection_matrix;
    param.point_a = in_pos_p1;
    param.point_b = in_pos_p2;
    param.thickness = in_thickness;
    segment_p->set_param(param);
}

void renderer_context::to_text_pipeline(const linear_color& in_color) {
    const auto text_p = aorii::get_renderer<dx_renderer>()->get_text_pipeline();
    switch_pipeline(text_p);

    sdf_text_pipeline::param param;
    param.projection_matrix = projection_matrix;
    text_p->set_param(param);

    sdf_text_pipeline::sdf_font_param font_param;
    font_param.smoothing = 1;
    font_param.thickness = 1;
    font_param.outline_width = 0;
    font_param.outline_color = in_color;
    text_p->set_sdf_font_param(font_param);

    text_p->set_glyph_texture(text->get_texture_array());
}

void renderer_context::make_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size,
                                 const linear_color& in_color, float in_angle, const aorii_vertex_param& in_param) {
    aorii_vertex v1{ { in_pos.x(), in_pos.y() }, { 0, 0 }, in_color, in_param }; // 左上角
    aorii_vertex v2{ { in_pos.x() + in_size.x(), in_pos.y() }, { 1, 0 }, in_color, in_param }; // 右上角
    aorii_vertex v3{ { in_pos.x(), in_pos.y() + in_size.y() }, { 0, 1 }, in_color, in_param }; // 左下角
    aorii_vertex v4{ { in_pos.x() + in_size.x(), in_pos.y() + in_size.y() }, { 1, 1 }, in_color, in_param }; // 右下角

    if (in_angle != 0) {
        auto center = in_pos + in_size * 0.5f;
        const Eigen::Affine2f transform =
            Eigen::Translation2f(center) *   // 平移到旋转中心
            Eigen::Rotation2Df(in_angle) *       // 旋转
            Eigen::Translation2f(-center);   // 平移回原点

        v1.position = transform * v1.position.homogeneous();
        v2.position = transform * v2.position.homogeneous();
        v3.position = transform * v3.position.homogeneous();
        v4.position = transform * v4.position.homogeneous();
    }

    const uint32_t base_index = vertices.size();
    vertices.push_back(v1);
    vertices.push_back(v2);
    vertices.push_back(v3);
    // vertices.push_back(v3);
    // vertices.push_back(v2);
    vertices.push_back(v4);

    triangles.push_back(aorii_triangle{ base_index + 0, base_index + 1, base_index + 2 });
    triangles.push_back(aorii_triangle{ base_index + 2, base_index + 1, base_index + 3 });
}

void renderer_context::rotate_vertex(const float in_angle, const Eigen::Vector2f& in_center) {
    const Eigen::Affine2f transform =
        Eigen::Translation<float, 2>(in_center) *   // 平移到旋转中心
        Eigen::Rotation2D<float>(in_angle) *       // 旋转
        Eigen::Translation<float, 2>(-in_center);   // 平移回原点

    for (auto& vertex : vertices) {
        vertex.position = transform * vertex.position;
    }
}
