#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/D3D12/D3D12Shader.h>

namespace Juliet::D3D12
{
    Shader* CreateShader(NonNullPtr<GPUDriver> /*driver*/, ByteBuffer shaderByteCode, ShaderCreateInfo& /*shaderCreateInfo*/)
    {
        if (!IsValid(shaderByteCode))
        {
            LogError(LogCategory::Graphics, "Invalid shader byte code");
            return nullptr;
        }

        size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size;
        auto   shader    = static_cast<D3D12Shader*>(Calloc(1, allocSize));
        if (!shader)
        {
            LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory");
            return nullptr;
        }

        // Uses the bytes after the struct to store the shader byte code.
        // TODO:MemoryArena Will use memory arena later that will do the same thing
        shader->ByteCode.Data = reinterpret_cast<Byte*>(shader + 1);
        shader->ByteCode.Size = shaderByteCode.Size;
        MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size);

        // Make sure the data is correctly copied
        if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0)
        {
            LogError(LogCategory::Graphics, "Memory copy failed");
            Free(shader);
            return nullptr;
        }

        return reinterpret_cast<Shader*>(shader);
    }

    void DestroyShader(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<Shader> shader)
    {
        auto d3d12shader = reinterpret_cast<D3D12Shader*>(shader.Get());
        Free(d3d12shader);
    }
} // namespace Juliet::D3D12
