#pragma once

#include "forward.hpp"
#include <vector>
#include <functional>
#include <glm/mat4x4.hpp>
#include "api/Buffers.hpp"
#include "api/Images.hpp"
#include "api/Models.hpp"

namespace tracy {
    class VkCtx;
}
typedef tracy::VkCtx* TracyVkCtxPtr;

namespace render::vk {
class SwapChain;
class Pipeline;
struct Subpass;

class CommandCenter final {
public:
    CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
    ~CommandCenter();

    void startRecording(uint32_t idx, VkRenderPass, VkExtent2D, const VoxelUBO&);
    void startWorldPass(uint32_t idx, const Subpass&);
    size_t recordModel(uint32_t idx, const Subpass &worldPass, const UniqueCurvaturePush&, const LodModel *const);
    void startEntityPass(uint32_t idx, const Subpass &entityPass);
    size_t recordModels(uint32_t idx, const Subpass &entityPass, const std::vector<glm::mat4>&, const Model *const);
    void startIndicPass(uint32_t idx, const Subpass&);
    size_t recordIndicator(uint32_t idx, const Subpass&, const ModelColorPush&, bool isCube);
    void recordPostprocess(uint32_t idx, const Subpass&, bool skybox);
    void recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function<void(VkCommandBuffer)> &);
    void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);

    void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias);
    void allocate(const std::vector<VkImageView>&, const Pipeline&, VkPhysicalDevice, VkExtent2D);
    void free();

private:

    VkDevice device;

    std::vector<VkFramebuffer> framebuffers;
    std::vector<VkFramebuffer> uiFramebuffers;

    VkFormat colorFormat;
    VkSampleCountFlagBits colorSamples;
    std::unique_ptr<Image> colorbuffer;
    VkFormat depthFormat;
    std::unique_ptr<Image> depthbuffer;

    VkQueue graphicsQueue;
    VkCommandPool graphicsPool;
    std::vector<VkCommandBuffer> graphicsBuffers;
    TracyVkCtxPtr tracyCtx;

    BufferGroup uniformBuffers;

    VkDescriptorPool descriptorPool;

    std::vector<VkDescriptorSet> voxelDescriptorSets;
    std::unique_ptr<TextureArray> voxelTextureAtlas;
    std::unique_ptr<TextureArray> voxelNormalAtlas;
    std::unique_ptr<TextureArray> voxelHOSAtlas;

    std::vector<VkDescriptorSet> indicDescriptorSets;
    std::unique_ptr<Shape> indicCubeBuffer;
    std::unique_ptr<Shape> indicSphereBuffer;

    std::vector<VkDescriptorSet> skyDescriptorSets;
    std::unique_ptr<TextureCube> skyboxTexture;
    std::unique_ptr<Shape> skyCubeBuffer;


    bool freed = true;
};
}