#include "pch.h"

#include "BufferUploader.h"
#include "BufferBuilder.h"
#include <glad/glad.h>
#include <spdlog/spdlog.h>
#include <glm/gtc/type_ptr.hpp>

namespace Vivid2D::Render::Buffer {

    // ==========================================================
    // RenderState 实现
    // ==========================================================

    void RenderState::saveCurrentState() {
        GLint currentProgram = 0;
        glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
        this->shaderProgram = static_cast<unsigned int>(currentProgram);

        GLint boundTexture = 0;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
        this->textureId = static_cast<unsigned int>(boundTexture);

        GLint activeTextureUnit = 0;
        glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureUnit);
        this->textureUnit = activeTextureUnit - GL_TEXTURE0;

        this->depthTest = glIsEnabled(GL_DEPTH_TEST);
        this->blending = glIsEnabled(GL_BLEND);

        while (glGetError() != GL_NO_ERROR) {}
    }

    void RenderState::applyState() const {
        // 恢复 Program
        if (shaderProgram != 0) {
            glUseProgram(shaderProgram);
        }

        // 恢复 Texture
        if (textureId != 0) {
            glActiveTexture(GL_TEXTURE0 + textureUnit);
            glBindTexture(GL_TEXTURE_2D, textureId);
        }

        // 恢复 Blending/Depth
        if (this->blending) {
            glEnable(GL_BLEND);
        }
        else {
            glDisable(GL_BLEND);
        }

        if (this->depthTest) {
            glEnable(GL_DEPTH_TEST);
        }
        else {
            glDisable(GL_DEPTH_TEST);
        }
    }


    // ==========================================================
    // BufferBuilder 实现
    // ==========================================================

    // 默认构造函数 (256 floats -> 64 顶点)
    BufferBuilder::BufferBuilder() : BufferBuilder(256) {}

    // 带容量构造函数
    BufferBuilder::BufferBuilder(int initialFloatCapacity)
        : array(std::max(16, initialFloatCapacity)), size(0), vertexCount(0)
    {
        // 默认绘制模式
        this->mode = GL_TRIANGLES;
        // 确保 array 初始是空的
        this->array.clear();
    }

    void BufferBuilder::begin(int glMode, int estimatedVertexCount) {
        this->mode = glMode;
        this->size = 0;
        this->vertexCount = 0;
        this->array.clear();

        // 保存当前渲染状态
        if (!stateSaved) {
            renderState.saveCurrentState();
            stateSaved = true;
        }

        if (estimatedVertexCount > 0) {
            this->array.reserve(estimatedVertexCount * COMPONENTS_PER_VERTEX);
        }
    }

    void BufferBuilder::setTexture(unsigned int textureId, int textureUnit) {
        this->renderState.textureId = textureId;
        this->renderState.textureUnit = textureUnit;
    }

    void BufferBuilder::setShader(unsigned int programId) {
        this->renderState.shaderProgram = programId;
    }

    void BufferBuilder::setColor(const glm::vec4& color) {
        this->renderState.color = color;
    }

    void BufferBuilder::setOpacity(float opacity) {
        this->renderState.opacity = opacity;
    }

    void BufferBuilder::vertex(float x, float y, float u, float v) {
        this->array.push_back(x);
        this->array.push_back(y);
        this->array.push_back(u);
        this->array.push_back(v);
        this->size = this->array.size();
        this->vertexCount++;
    }

    std::unique_ptr<BuiltBuffer> BufferBuilder::end() {
        if (vertexCount == 0) return nullptr;

        RenderSystem::assertOnRenderThread();

        // 1. 创建和绑定 GPU 资源
        unsigned int vao = RenderSystem::GenVertexArrays();
        unsigned int vbo = RenderSystem::GenBuffers();

        RenderSystem::BindVertexArray(vao);
        RenderSystem::BindBuffer(GL_ARRAY_BUFFER, vbo);

        // 2. 上传数据
        // 假设 RenderSystem 已经定义了 GL_ARRAY_BUFFER 和 GL_DYNAMIC_DRAW
        RenderSystem::BufferData(GL_ARRAY_BUFFER, this->array.size() * sizeof(float),
            this->array.data(), GL_DYNAMIC_DRAW);

        // 3. 设置顶点属性 (Location 0: Position, Location 1: TexCoord)
        // Position (location 0): 2 floats, offset 0
        RenderSystem::enableVertexAttribArray(0);
        RenderSystem::vertexAttribPointer(0, 2, GL_FLOAT, false,
            COMPONENTS_PER_VERTEX * sizeof(float), 0);

        // Texture Coords (location 1): 2 floats, offset 2 * sizeof(float)
        RenderSystem::enableVertexAttribArray(1);
        RenderSystem::vertexAttribPointer(1, 2, GL_FLOAT, false,
            COMPONENTS_PER_VERTEX * sizeof(float),
            reinterpret_cast<const void*>(2 * sizeof(float)));

        // 4. 解绑
        RenderSystem::BindBuffer(GL_ARRAY_BUFFER, 0);
        RenderSystem::BindVertexArray(0);

        // 5. 返回 BuiltBuffer
        RenderState stateCopy = renderState.copy();
        stateSaved = false;

        return std::make_unique<BuiltBuffer>(vao, vbo, vertexCount, mode, stateCopy);
    }

    void BufferBuilder::endImmediate() {
        std::unique_ptr<BuiltBuffer> buffer = end();
        if (buffer != nullptr) {
            BufferUploader::drawWithShader(std::move(buffer));
        }
    }

    void BufferBuilder::dispose(const BuiltBuffer* buffer) {
        if (buffer != nullptr) {
            RenderSystem::DeleteVertexArrays(buffer->vao);
            RenderSystem::DeleteBuffers(buffer->vbo);
        }
    }

    void BufferBuilder::clear() {
        this->array.clear();
        this->size = 0;
        this->vertexCount = 0;
    }
} // namespace Buffer