#pragma once
#include <d3d11.h>

#include "core/renderer/renderer.h"
#include "pipeline/dx_rect_pipeline.h"
#include "pipeline/dx_rounded_rect_pipeline.h"
#include "pipeline/dx_sdf_text_pipeline.h"
#include "pipeline/dx_segment_pipeline.h"
#include "pipeline/dx_texture_pipeline.h"

class dx_window;

class dx_renderer : public renderer {
public:
    bool init() override;
    void destroy() override;
    bool render() override;

    renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) override;
    renderer_texture_array* 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) override;

    [[nodiscard]] ID3D11Device* get_d3d_device() const { return device; }
    [[nodiscard]] ID3D11DeviceContext* get_d3d_context() const { return context; }

    rect_pipeline* get_rect_pipeline() override { return &rect_p; }
    rounded_rect_pipeline* get_rounded_rect_pipeline() override { return &rounded_rect_p; }
    texture_pipeline* get_texture_pipeline() override { return &texture_p; }
    segment_pipeline* get_segment_pipeline() override { return &segment_p; }
    sdf_text_pipeline* get_text_pipeline() override { return &text_p; }

    Eigen::Matrix4f make_projection_matrix(const Eigen::Vector2i& size) override;

    [[nodiscard]] ID3D11BlendState* get_blend_state() const { return blend_state; }

    std::vector<int8_t> load_shader(const std::string& shader_name) override;

    renderer_buffer* create_buffer(buffer_type in_buffer_type, int32_t in_element_byte, int32_t in_size) override;
private:
    renderer_window* create_window() override;

    bool create_device();

    ID3D11Device* device = nullptr;
    ID3D11DeviceContext* context = nullptr;
    ID3D11BlendState* blend_state = nullptr;

    dx_rect_pipeline rect_p;
    dx_rounded_rect_pipeline rounded_rect_p;
    dx_texture_pipeline texture_p;
    dx_segment_pipeline segment_p;
    dx_sdf_text_pipeline text_p;
};

inline DXGI_FORMAT get_dxgi_format(texture_format format) {
       switch (format) {
        // 8-bit formats
        case texture_format::R8_UNORM:
            return DXGI_FORMAT_R8_UNORM;
        case texture_format::R8_SNORM:
            return DXGI_FORMAT_R8_SNORM;
        case texture_format::R8_UINT:
            return DXGI_FORMAT_R8_UINT;
        case texture_format::R8_SINT:
            return DXGI_FORMAT_R8_SINT;

        // 16-bit formats
        case texture_format::RG8_UNORM:
            return DXGI_FORMAT_R8G8_UNORM;
        case texture_format::RG8_SNORM:
            return DXGI_FORMAT_R8G8_SNORM;
        case texture_format::RG8_UINT:
            return DXGI_FORMAT_R8G8_UINT;
        case texture_format::RG8_SINT:
            return DXGI_FORMAT_R8G8_SINT;

        // 24-bit formats
        case texture_format::RGB8_UNORM:
            return DXGI_FORMAT_B8G8R8X8_UNORM; // Note: DXGI doesn't have a direct RGB8 format

        // 32-bit formats
        case texture_format::RGBA8_UNORM:
            return DXGI_FORMAT_R8G8B8A8_UNORM;
        case texture_format::RGBA8_SNORM:
            return DXGI_FORMAT_R8G8B8A8_SNORM;
        case texture_format::RGBA8_UINT:
            return DXGI_FORMAT_R8G8B8A8_UINT;
        case texture_format::RGBA8_SINT:
            return DXGI_FORMAT_R8G8B8A8_SINT;

        // SRGB formats
        case texture_format::SRGB8:
            return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; // Note: Approximation
        case texture_format::SRGB8_ALPHA8:
            return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;

        // 16-bit float formats
        case texture_format::R16_FLOAT:
            return DXGI_FORMAT_R16_FLOAT;
        case texture_format::RG16_FLOAT:
            return DXGI_FORMAT_R16G16_FLOAT;
        case texture_format::RGBA16_FLOAT:
            return DXGI_FORMAT_R16G16B16A16_FLOAT;

        // 32-bit float formats
        case texture_format::R32_FLOAT:
            return DXGI_FORMAT_R32_FLOAT;
        case texture_format::RG32_FLOAT:
            return DXGI_FORMAT_R32G32_FLOAT;
        case texture_format::RGB32_FLOAT:
            return DXGI_FORMAT_R32G32B32_FLOAT;
        case texture_format::RGBA32_FLOAT:
            return DXGI_FORMAT_R32G32B32A32_FLOAT;

        // Integer formats
        case texture_format::R16_UINT:
            return DXGI_FORMAT_R16_UINT;
        case texture_format::R16_SINT:
            return DXGI_FORMAT_R16_SINT;
        case texture_format::RG16_UINT:
            return DXGI_FORMAT_R16G16_UINT;
        case texture_format::RG16_SINT:
            return DXGI_FORMAT_R16G16_SINT;
        case texture_format::RGBA16_UINT:
            return DXGI_FORMAT_R16G16B16A16_UINT;
        case texture_format::RGBA16_SINT:
            return DXGI_FORMAT_R16G16B16A16_SINT;
        case texture_format::R32_UINT:
            return DXGI_FORMAT_R32_UINT;
        case texture_format::R32_SINT:
            return DXGI_FORMAT_R32_SINT;
        case texture_format::RG32_UINT:
            return DXGI_FORMAT_R32G32_UINT;
        case texture_format::RG32_SINT:
            return DXGI_FORMAT_R32G32_SINT;
        case texture_format::RGBA32_UINT:
            return DXGI_FORMAT_R32G32B32A32_UINT;
        case texture_format::RGBA32_SINT:
            return DXGI_FORMAT_R32G32B32A32_SINT;

        // Depth/stencil formats
        case texture_format::D16_UNORM:
            return DXGI_FORMAT_D16_UNORM;
        case texture_format::D24_UNORM_S8_UINT:
            return DXGI_FORMAT_D24_UNORM_S8_UINT;
        case texture_format::D32_FLOAT:
            return DXGI_FORMAT_D32_FLOAT;
        case texture_format::D32_FLOAT_S8X24_UINT:
            return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;

        // Compressed formats
        case texture_format::BC1_UNORM:
            return DXGI_FORMAT_BC1_UNORM;
        case texture_format::BC1_UNORM_SRGB:
            return DXGI_FORMAT_BC1_UNORM_SRGB;
        case texture_format::BC2_UNORM:
            return DXGI_FORMAT_BC2_UNORM;
        case texture_format::BC2_UNORM_SRGB:
            return DXGI_FORMAT_BC2_UNORM_SRGB;
        case texture_format::BC3_UNORM:
            return DXGI_FORMAT_BC3_UNORM;
        case texture_format::BC3_UNORM_SRGB:
            return DXGI_FORMAT_BC3_UNORM_SRGB;
        case texture_format::BC4_UNORM:
            return DXGI_FORMAT_BC4_UNORM;
        case texture_format::BC4_SNORM:
            return DXGI_FORMAT_BC4_SNORM;
        case texture_format::BC5_UNORM:
            return DXGI_FORMAT_BC5_UNORM;
        case texture_format::BC5_SNORM:
            return DXGI_FORMAT_BC5_SNORM;
        case texture_format::BC6H_UF16:
            return DXGI_FORMAT_BC6H_UF16;
        case texture_format::BC6H_SF16:
            return DXGI_FORMAT_BC6H_SF16;
        case texture_format::BC7_UNORM:
            return DXGI_FORMAT_BC7_UNORM;
        case texture_format::BC7_UNORM_SRGB:
            return DXGI_FORMAT_BC7_UNORM_SRGB;

        default:
            assert(0);
            return DXGI_FORMAT_UNKNOWN;
    }
}
