#pragma once

#include <Core/Container/Vector.h>
#include <Core/Math/Matrix.h>
#include <Graphics/VertexData.h>
#include <Juliet.h>

namespace Juliet
{
    struct GraphicsTransferBuffer;
    struct RenderPass;
    struct CommandList;
    struct GraphicsBuffer;
    struct Window;
    struct GraphicsPipeline;
    struct GraphicsDevice;
    struct Mesh;

    using MeshID = index_t;

    constexpr size_t kGeometryPage       = Megabytes(64);
    constexpr size_t kIndexPage          = Megabytes(32);
    constexpr size_t kDefaultMeshNumber  = 500;
    constexpr size_t kDefaultVertexCount = 2'000'000;  // Fit less than one geometry page
    constexpr size_t kDefaultIndexCount  = 16'000'000; // Fit less than one index page

    struct MeshRenderer
    {
        // Note we prevent realloc for now.
        VectorArena<Mesh, kDefaultMeshNumber, false>    Meshes;
        VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
        VectorArena<Index, kDefaultIndexCount, false>   Indices;

        GraphicsBuffer*         VertexBuffer;
        GraphicsBuffer*         IndexBuffer;
        GraphicsTransferBuffer* StreamCopyBuffer;
        GraphicsTransferBuffer* LoadCopyBuffer;

        GraphicsDevice*   Device;
        GraphicsPipeline* Pipeline;
    };

    struct PushData
    {
        Matrix ViewProjection;
        Matrix Model;
        uint32 BufferIndex;
    };

    [[nodiscard]] JULIET_API bool InitializeMeshRenderer(NonNullPtr<Arena> arena, NonNullPtr<GraphicsDevice> device,
                                                         NonNullPtr<Window> window);
    JULIET_API void               ShutdownMeshRenderer();
    JULIET_API void               LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList);
    JULIET_API void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData);

    // Utils
    [[nodiscard]] JULIET_API MeshID AddCube();
    [[nodiscard]] JULIET_API MeshID AddQuad();
    JULIET_API void                  SetMeshTransform(MeshID id, const Matrix& transform);

#if ALLOW_SHADER_HOT_RELOAD
    JULIET_API void ReloadMeshRendererShaders();
#endif

} // namespace Juliet
