#ifndef RENDER_MATERIAL_H
#define RENDER_MATERIAL_H

#include <string>
#include <vector>
#include <render_type_def.h>

#include "shared_model.h"
#include "shader.h"

#include "texture.h"



class Material {
public:
    // 第一版采用 ORM 打包纹理：R=AO, G=Roughness, B=Metallic。
    struct PBRMaterialDesc {
        DirectX::XMFLOAT4 baseColorFactor{0.1f,0.1f,0.1f,1.0f};
        DirectX::XMFLOAT3 emissiveFactor{0.0f, 0.0f, 0.0f};

        float metallicFactor = 1.0f;
        float roughnessFactor = 1.0f;
        float normalScale = 1.0f;
        float occlusionStrength = 1.0f;

        Texture2D *baseColorTexture = nullptr;
        Texture2D *normalTexture = nullptr;
        Texture2D *ormTexture = nullptr;
        Texture2D *emissiveTexture = nullptr;
    };

public:
    static Material *S_CreateMaterial(const std::string &name, const Shader *shader,
                                      ID3D11Device *device, PBRMaterialDesc desc = {});
    static Material *S_GetMaterial(const std::string &name);

public:
    [[nodiscard]] const Shader::CBufferDesc *GetCbDesc() const noexcept { return m_perMatDesc; }
    [[nodiscard]] const Shader *GetShader() const noexcept { return m_shader; }

    bool Bind(ID3D11DeviceContext *ctx);

    bool SetPermatCbProp(int id, const Z::ShaderInfo::Value &value);
    bool SetPermatCbPropRaw(std::string_view propName, const void *data, std::size_t byteSize);
    // [ADD] 类型安全的常用入口；T 必须和 HLSL 变量尺寸完全一致。
    template<typename T>
    bool SetPermatCbProp(std::string_view propertyName, const T &value) {
        static_assert(std::is_trivially_copyable_v<T>);
        return SetPermatCbPropRaw(propertyName, &value, sizeof(T));
    }

    bool AssignTexture(Texture2D *tex, int index);
    bool AssignTexture(TextureCube *tex, int index);//[add]
    bool AssignTexture(std::string_view shaderTextureName, Texture2D *tex);
    bool AssignTexture(std::string_view shaderTextureName, TextureCube *tex);//[add]
    bool AssignTextureSRV(std::string_view shaderTextureName, ID3D11ShaderResourceView *srv);

private:
    // [ADD]
    struct TextureBinding {
        Shader::TexBufDesc desc{};
        Texture2D *texture2D = nullptr;
        TextureCube *textureCube = nullptr; //[add]
        ID3D11ShaderResourceView *srv = nullptr;
    };

    bool InitGpuResources(ID3D11Device *device);
    // [PBR-ADD]
    [[nodiscard]] const Shader::PropertyDesc *FindPerMatProperty(std::string_view propName) const;
    // [PBR-ADD]
    [[nodiscard]] TextureBinding *FindTextureBinding(std::string_view shaderTextureName);

public:

private:
    const Shader *m_shader{};

    bool b_dirty{true};
    std::string m_name;

    //CBPerMat(b1)
    const Shader::CBufferDesc *m_perMatDesc{}; // b1(CBPerMat)的描述符,可能为nullptr
    std::vector<std::byte> m_perMatCBData{}; // CBUFFER 的 CPU数据,每帧从这里上传给GPU buffer,可能为空
    Microsoft::WRL::ComPtr<ID3D11Buffer> m_perMatCbuffer{}; //CBUFFER 的GPU句柄, 可能为空

    // Texture资源
    std::vector<TextureBinding> m_textureBindings{};
    std::unordered_map<std::string, std::size_t> m_textureName2Index{};


};













#endif //RENDER_MATERIAL_H
