#include "pch.h"

#include "BufferUploader.h"

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

namespace Vivid2D::Render::Buffer {

    void BufferUploader::applyRenderState(const RenderState& state) {
        if (state.textureId != 0) {
            RenderSystem::activeTexture(GL_TEXTURE0 + state.textureUnit);
            RenderSystem::bindTexture(state.textureId);
        }
        unsigned int currentProgram = 0;
        if (state.shaderProgram != 0) {
            currentProgram = state.shaderProgram;
            RenderSystem::useProgram(state.shaderProgram); // <--- 这里使用了 Program
        }
        else {
            // 如果状态中没有指定着色器，尝试获取当前绑定的着色器程序
            GLint programId = 0;
            glGetIntegerv(GL_CURRENT_PROGRAM, &programId);
            currentProgram = static_cast<unsigned int>(programId);
        }
        if (currentProgram != 0) {
            GLint colorLoc = RenderSystem::getUniformLocation(currentProgram, "uColor");
            if (colorLoc != -1) {
                RenderSystem::uniform4f(colorLoc,
                    state.color.x, state.color.y, state.color.z, state.color.w);
            }
            else {
                spdlog::warn("BufferUploader::applyRenderState: Uniform 'uColor' not found in program ID: {}.", currentProgram);
            }
        }
        else {
            spdlog::warn("BufferUploader::applyRenderState: No shader program available for color setting.");
        }

        // 4. 应用混合模式
        if (state.blending) {
            RenderSystem::enableBlend();
            // 假设 RenderSystem::defaultBlendFunc() 封装了 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            RenderSystem::defaultBlendFunc();
        }
        else {
            RenderSystem::disableBlend();
        }

        // 5. 应用深度测试
        if (state.depthTest) {
            RenderSystem::enableDepthTest();
        }
        else {
            RenderSystem::disableDepthTest();
        }
    }

    void BufferUploader::restoreRenderState(const RenderState& previousState) {
        previousState.applyState();
    }


    // ==========================================================
    // 核心逻辑实现
    // ==========================================================

    void BufferUploader::drawWithShader(std::unique_ptr<BuiltBuffer> buffer) {
        if (!buffer) return;
        RenderSystem::assertOnRenderThread();
        RenderState currentState;
        currentState.saveCurrentState();
        try {
            const RenderState& bufferState = buffer->renderState;
            applyRenderState(bufferState);
            if (buffer->vao != 0 && buffer->vbo != 0) {
                RenderSystem::BindVertexArray(buffer->vao);
                RenderSystem::BindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
                RenderSystem::enableVertexAttribArray(0);
                RenderSystem::enableVertexAttribArray(1);
            }

            if (buffer->vertexCount > 0) {
                RenderSystem::drawArrays(buffer->mode, 0, buffer->vertexCount);
            }

            if (buffer->vao != 0) {
                RenderSystem::disableVertexAttribArray(0);
                RenderSystem::disableVertexAttribArray(1);
                RenderSystem::BindBuffer(GL_ARRAY_BUFFER, 0);
                RenderSystem::BindVertexArray(0);
            }
        }
        catch (const std::exception& e) {
            spdlog::error("BufferUploader drawing failed: {}", e.what());
        }
        restoreRenderState(currentState);
        BufferBuilder::dispose(buffer.get());
    }

} // namespace Buffer