#include "FrameBuffer.hpp"
#include "Debug.hpp"

TSE::GLFW::FrameBuffer::FrameBuffer(const Vector2 &size)
{
    width = size.x;
    height = size.y;
    CreateFBTexture();
    for (auto const& i : objectsToResize)
    {
        i->OnResize(size.x, size.y, this);
    }
    Initialize();
}

void TSE::GLFW::FrameBuffer::Bind()
{
    glBindFramebuffer(GL_FRAMEBUFFER, bufferID);
}

void TSE::GLFW::FrameBuffer::Unbind()
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

TSE::GLFW::FrameBuffer::~FrameBuffer()
{
    glDeleteFramebuffers(1,&bufferID);
    glDeleteTextures(1, &textureID);
    glDeleteRenderbuffers(1, &depthRboID);
}

void TSE::GLFW::FrameBuffer::Resize(Vector2 size)
{
    width = size.x;
    height = size.y;
    shouldResize = true;
}

void TSE::GLFW::FrameBuffer::Update()
{
    if (!shouldResize) return;
    shouldResize = false;
    CreateFBTexture();
    for (auto const& i : objectsToResize)
    {
        i->OnResize(width, height, this);
    }
}

TSE::uint TSE::GLFW::FrameBuffer::GetTextureId() const
{
    return textureID;
}

TSE::Vector2 TSE::GLFW::FrameBuffer::GetSize() const
{
    return {width, height};
}

void TSE::GLFW::FrameBuffer::Initialize()
{
    glGenFramebuffers(1, &bufferID);
    Bind();
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboID);
    
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        TSE_ERROR("Failed to create OpenGL FBO.");
        TSE_LOG(std::to_string(glGetError()));
    }
    Unbind();
}

void TSE::GLFW::FrameBuffer::LoadFBTexture()
{
    glBindTexture(GL_TEXTURE_2D, textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glBindRenderbuffer(GL_RENDERBUFFER, depthRboID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}

void TSE::GLFW::FrameBuffer::CreateFBTexture()
{
    glViewport(0,0, width, height);
    //resize
    if(textureID == 0)
        glGenTextures(1, &textureID);
    if(depthRboID == 0)
        glGenRenderbuffers(1, &depthRboID);
    LoadFBTexture();
}
