//
// Created by sfd on 25-5-25.
//

#include "OpenGLFrameBuffer.h"
#include <glad/glad.h>
#include <Hazel/Core/Log.h>

namespace Hazel
{

    static constexpr uint32_t s_MaxFrameBufferSize = 8192;

    OpenGLFrameBuffer::OpenGLFrameBuffer(const FrameBufferSpecification& spec)
        : m_Specification(spec)
    {
        Invalidata();
    }

    OpenGLFrameBuffer::~OpenGLFrameBuffer()
    {
        glDeleteFramebuffers(1, &m_RendererID);
        glDeleteTextures(1, &m_ColorAttachment);
        glDeleteTextures(1, &m_DepthAttachment);
    }

    void OpenGLFrameBuffer::Bind()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
    }

    void OpenGLFrameBuffer::UnBind()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    void OpenGLFrameBuffer::Resize(const uint32_t width, const uint32_t height)
    {
        if (width == 0 || height == 0)
        {
            HZ_CORE_WARN("attempting to resize framebuffer to {0}x{1}", width, height);
        }

        m_Specification.Width = width > s_MaxFrameBufferSize ? s_MaxFrameBufferSize : width;
        m_Specification.Height = height > s_MaxFrameBufferSize ? s_MaxFrameBufferSize : height;

        Invalidata();
    }

    void OpenGLFrameBuffer::Invalidata()
    {

        if (m_RendererID)
        {
            glDeleteFramebuffers(1, &m_RendererID);
            glDeleteTextures(1, &m_ColorAttachment);
            glDeleteTextures(1, &m_DepthAttachment);

            glViewport(0, 0, m_Specification.Width, m_Specification.Height);
        }

        glCreateFramebuffers(1, &m_RendererID);
        glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);

        glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment);
        glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Specification.Width, m_Specification.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);

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0);


        glCreateTextures(GL_TEXTURE_2D, 1, &m_DepthAttachment);
        glBindTexture(GL_TEXTURE_2D, m_DepthAttachment);
        glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height);
        // glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0);

        {
            GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
            switch(status) {
            case GL_FRAMEBUFFER_COMPLETE:
                break;
            case GL_FRAMEBUFFER_UNDEFINED: /* 默认帧缓冲不存在 */
                HZ_CORE_ERROR("默认缓冲不存在!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: /* 附件不完整 */
                HZ_CORE_ERROR("附件不完整!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: /* 缺少颜色附件 */
                HZ_CORE_ERROR("附件不完整!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: /* 颜色附件索引无效 */
                HZ_CORE_ERROR("颜色附件索引无效!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: /* 读取缓冲区设置错误 */
                HZ_CORE_ERROR("读取缓冲区设置错误!"); break;
            case GL_FRAMEBUFFER_UNSUPPORTED: /* 格式组合不支持 */
                HZ_CORE_ERROR("格式组合不支持!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: /* 多重采样不一致 */
                HZ_CORE_ERROR("多重采样不一致!"); break;
            case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: /* 图层目标不完整 */
                HZ_CORE_ERROR("图层目标不完整!"); break;
            default: /* 未知错误 */
                HZ_CORE_ERROR("未知错误!"); break;

            }
        }

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
}
