#include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/utils/logger.h>

namespace extra2d {

// ============================================================================
// GLFramebuffer 实现
// ============================================================================

GLFramebuffer::GLFramebuffer() = default;

GLFramebuffer::~GLFramebuffer() {
    shutdown();
}

bool GLFramebuffer::init(const FramebufferDesc& desc) {
    if (fboID_ != 0) {
        shutdown();
    }

    width_ = desc.width;
    height_ = desc.height;
    numColorAttachments_ = desc.colorAttachments;
    hasDepth_ = desc.hasDepth;
    hasStencil_ = desc.hasStencil;

    // 限制颜色附件数
    if (numColorAttachments_ > MAX_COLOR_ATTACHMENTS) {
        numColorAttachments_ = MAX_COLOR_ATTACHMENTS;
    }

    // 生成 FBO
    glGenFramebuffers(1, &fboID_);
    if (fboID_ == 0) {
        E2D_LOG_ERROR("Failed to generate OpenGL framebuffer");
        return false;
    }

    E2D_LOG_DEBUG("GLFramebuffer created: ID={}, Size={}x{}, ColorAttachments={}",
                  fboID_, width_, height_, numColorAttachments_);

    return true;
}

void GLFramebuffer::shutdown() {
    if (fboID_ != 0) {
        glDeleteFramebuffers(1, &fboID_);
        E2D_LOG_DEBUG("GLFramebuffer destroyed: ID={}", fboID_);
        fboID_ = 0;
    }

    // 清理纹理引用
    for (auto& tex : colorTextures_) {
        tex.reset();
    }
    depthTexture_.reset();
    depthStencilTexture_.reset();

    hasInternalTextures_ = false;
}

void GLFramebuffer::bind() {
    if (fboID_ != 0) {
        glBindFramebuffer(GL_FRAMEBUFFER, fboID_);
    }
}

void GLFramebuffer::unbind() {
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void GLFramebuffer::attachColorTexture(Ptr<Texture> texture, int attachment) {
    if (fboID_ == 0 || !texture || attachment < 0 || attachment >= MAX_COLOR_ATTACHMENTS) {
        return;
    }

    bind();

    // 获取 OpenGL 纹理 ID
    GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle()));

    glFramebufferTexture2D(GL_FRAMEBUFFER, getColorAttachment(attachment),
                           GL_TEXTURE_2D, texID, 0);

    colorTextures_[attachment] = texture;

    unbind();
}

void GLFramebuffer::attachDepthTexture(Ptr<Texture> texture) {
    if (fboID_ == 0 || !texture) {
        return;
    }

    bind();

    // 获取 OpenGL 纹理 ID
    GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle()));

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                           GL_TEXTURE_2D, texID, 0);

    depthTexture_ = texture;
    hasDepth_ = true;
    hasStencil_ = false;

    unbind();
}

void GLFramebuffer::attachDepthStencilTexture(Ptr<Texture> texture) {
    if (fboID_ == 0 || !texture) {
        return;
    }

    bind();

    // 获取 OpenGL 纹理 ID
    GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle()));

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                           GL_TEXTURE_2D, texID, 0);

    depthStencilTexture_ = texture;
    hasDepth_ = true;
    hasStencil_ = true;

    unbind();
}

bool GLFramebuffer::isComplete() {
    if (fboID_ == 0) {
        return false;
    }

    bind();
    bool complete = checkStatus();
    unbind();

    return complete;
}

Ptr<Texture> GLFramebuffer::getColorTexture(int attachment) const {
    if (attachment >= 0 && attachment < MAX_COLOR_ATTACHMENTS) {
        return colorTextures_[attachment];
    }
    return nullptr;
}

Ptr<Texture> GLFramebuffer::getDepthTexture() const {
    return depthTexture_;
}

void GLFramebuffer::clear(const Color& color, bool clearColor, 
                          bool clearDepth, bool clearStencil) {
    if (fboID_ == 0) {
        return;
    }

    bind();

    GLbitfield mask = 0;

    if (clearColor) {
        mask |= GL_COLOR_BUFFER_BIT;
        glClearColor(color.r, color.g, color.b, color.a);
    }

    if (clearDepth) {
        mask |= GL_DEPTH_BUFFER_BIT;
        glClearDepthf(1.0f);
    }

    if (clearStencil) {
        mask |= GL_STENCIL_BUFFER_BIT;
        glClearStencil(0);
    }

    if (mask != 0) {
        glClear(mask);
    }

    unbind();
}

void GLFramebuffer::setViewport(int x, int y, int width, int height) {
    glViewport(x, y, width, height);
}

bool GLFramebuffer::readPixels(int x, int y, int width, int height, 
                               std::vector<uint8_t>& outData) {
    if (fboID_ == 0 || width <= 0 || height <= 0) {
        return false;
    }

    // 计算需要的缓冲区大小 (RGBA8)
    size_t dataSize = width * height * 4;
    outData.resize(dataSize);

    bind();
    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, outData.data());
    unbind();

    return true;
}

bool GLFramebuffer::createWithTextures(int width, int height, 
                                       PixelFormat colorFormat,
                                       PixelFormat depthFormat) {
    FramebufferDesc desc;
    desc.width = width;
    desc.height = height;
    desc.colorAttachments = 1;
    desc.hasDepth = (depthFormat != PixelFormat::RGBA8);
    desc.hasStencil = (depthFormat == PixelFormat::Depth24Stencil8);

    if (!init(desc)) {
        return false;
    }

    hasInternalTextures_ = true;

    // 创建颜色纹理
    // 注意：这里简化处理，实际应该通过纹理工厂创建
    // 暂时返回 true，实际纹理创建由调用者处理

    return true;
}

bool GLFramebuffer::checkStatus() {
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    switch (status) {
        case GL_FRAMEBUFFER_COMPLETE:
            return true;
        case GL_FRAMEBUFFER_UNDEFINED:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
            break;
#ifndef GL_ES_VERSION_2_0
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
            break;
#endif
        case GL_FRAMEBUFFER_UNSUPPORTED:
            E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNSUPPORTED");
            break;
        default:
            E2D_LOG_ERROR("Framebuffer incomplete: Unknown error {}", status);
            break;
    }

    return false;
}

GLenum GLFramebuffer::getColorAttachment(int index) {
    return GL_COLOR_ATTACHMENT0 + index;
}

} // namespace extra2d
