#include "dx_renderer.h"

#include <fstream>
#include <GLFW/glfw3.h>

#include "dx_buffer.h"
#include "dx_texture.h"
#include "dx_texture_array.h"
#include "dx_window.h"
#include "core/window/window_manager.h"
#include "spdlog/spdlog.h"

bool dx_renderer::init() {
    if (!glfwInit()) return false;
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

    if (!create_device()) return false;

    D3D11_BLEND_DESC blend_desc = {};
    blend_desc.RenderTarget[0].BlendEnable = TRUE;
    blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
    blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
    blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
    blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
    blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
    blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    auto hr = device->CreateBlendState(&blend_desc, &blend_state);
    if (FAILED(hr)) {
        spdlog::critical("无法创建混合状态, 错误: {0}", hr);
        return false;
    }

    rect_p.init();
    rounded_rect_p.init();
    texture_p.init();
    segment_p.init();
    text_p.init();

    return true;
}

void dx_renderer::destroy() {
    if (blend_state) blend_state->Release();
    rect_p.destroy();
    rounded_rect_p.destroy();
    texture_p.destroy();
    glfwTerminate();
}

bool dx_renderer::render() {
    const auto& all_window = aorii::get_all_window();
    for (const auto& window : all_window) {
        window->begin_frame();
        window->end_frame();
    }
    return true;
}

renderer_texture* dx_renderer::create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) {
    return new dx_texture({ in_size_width, in_size_height }, in_format, in_memory_type);
}

renderer_texture_array* dx_renderer::create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) {
    return new dx_texture_array({ in_size_width, in_size_height }, in_format, in_count, in_memory_type);
}

Eigen::Matrix4f dx_renderer::make_projection_matrix(const Eigen::Vector2i& size) {
    // 创建一个单位矩阵
    Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();

    // 缩放因子
    const float scale_x = 2.0f / static_cast<float>(size.x());
    const float scale_y = -2.0f / static_cast<float>(size.y());  // Y轴翻转，因为窗口坐标系Y轴向下

    // 平移因子
    constexpr float translate_x = -1.0f;
    constexpr float translate_y = 1.0f;

    // 设置缩放
    matrix(0, 0) = scale_x;
    matrix(1, 1) = scale_y;

    // 设置平移
    matrix(0, 3) = translate_x;
    matrix(1, 3) = translate_y;

    return matrix;
}

std::vector<int8_t> dx_renderer::load_shader(const std::string& shader_name) {
    auto file_pathname = aorii::get_shader_path(shader_name).generic_string() + ".dxbc";
    std::ifstream file(file_pathname, std::ios::binary);
    return { (std::istreambuf_iterator(file)), std::istreambuf_iterator<char>() };
}

renderer_buffer* dx_renderer::create_buffer(buffer_type in_buffer_type, int32_t in_element_byte, int32_t in_size) {
    return new dx_buffer(in_buffer_type, in_element_byte, in_size);
}

renderer_window* dx_renderer::create_window() {
    return new dx_window();
}

bool dx_renderer::create_device() {
    constexpr D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 };
#ifdef DEBUG
    int flags = D3D11_CREATE_DEVICE_DEBUG;
#else
    int flags = 0;
#endif
    const auto result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, featureLevels, 2,
                                          D3D11_SDK_VERSION, &device, nullptr, &context);
    return SUCCEEDED(result);
}
