#include "DeerRender/FrameBuffer.h"
#include <unordered_map>

#define FRAME_BUFFER_MAX_COUNT 256

namespace Deer {
    namespace FrameBufferManager {
        struct FrameBufferContainer {
            FrameBuffer* frameBuffer_data = nullptr;
            std::string frameBuffer_name;
        };

        uint16_t maxFrameBufferId = 1;
        FrameBufferContainer frameBuffers[FRAME_BUFFER_MAX_COUNT]{};
        std::unordered_map<std::string, uint16_t> frameBuffers_name_id_map;
    }

    uint16_t FrameBufferManager::createRGBA8FrameBuffer(std::string& name, int x, int y) {
        FrameBufferSpecification specs(
            x, y,
            {TextureBufferType::RGBA8}, 4,
            false);
        
        FrameBuffer* frameBuffer = FrameBuffer::create(specs);
        
        uint16_t frameBufferId = maxFrameBufferId;
        maxFrameBufferId++;

        frameBuffers[frameBufferId].frameBuffer_data = frameBuffer;
        frameBuffers[frameBufferId].frameBuffer_name = name;

        frameBuffers_name_id_map[name] = frameBufferId;
        return frameBufferId;
    }

    void FrameBufferManager::resizeFrameBuffer(uint16_t frameBufferId, int x, int y) {
        FrameBuffer* frameBuffer = frameBuffers[frameBufferId].frameBuffer_data;

        frameBuffer->resize(x, y);
    }

    int FrameBufferManager::getFrameBufferWidth(uint16_t frameBufferId) {
        FrameBuffer* frameBuffer = frameBuffers[frameBufferId].frameBuffer_data;

        return frameBuffer->getSpecification().width;
    }

    int FrameBufferManager::getFrameBufferHeight(uint16_t frameBufferId) {
        FrameBuffer* frameBuffer = frameBuffers[frameBufferId].frameBuffer_data;

        return frameBuffer->getSpecification().height;
    }

    const std::string& FrameBufferManager::getFrameBufferName(uint16_t id) {
        DEER_CORE_ASSERT(id >= 0 && id < maxFrameBufferId, "Invalid frame buffer id {0}", id);

        return frameBuffers[id].frameBuffer_name;
    }

    FrameBuffer& FrameBufferManager::getFrameBuffer(uint16_t id) {
        DEER_CORE_ASSERT(id > 0 && id < maxFrameBufferId, "Invalid frame buffer id {0}", id);

        return *frameBuffers[id].frameBuffer_data;
    }

    uint16_t FrameBufferManager::getFrameBufferId(std::string& name) {
        return frameBuffers_name_id_map[name];
    }

    void FrameBufferManager::unloadAllFrameBuffer() {
        for (int x = 1; x < maxFrameBufferId; x++) {
            delete frameBuffers[x].frameBuffer_data;
            frameBuffers[x].frameBuffer_data = nullptr;
        }

        frameBuffers_name_id_map.clear();

        maxFrameBufferId = 1;
        frameBuffers[0].frameBuffer_data = nullptr;
        frameBuffers[0].frameBuffer_name = "NULL";
        frameBuffers_name_id_map["NULL"] = 0;
    }
}