#include "RenderManager.h"
#include <fstream>
#include "Texture.h"

RenderManager::RenderManager(SDL_Window *window)
{
    _window = window;
    // 创建OpenGL上下文
    _ctx = SDL_GL_CreateContext(window);
    if (!_ctx)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL context create failed: %s\n", SDL_GetError());
    }

    // 初始化GLAD
    if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress))
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GLAD init failed!\n");
    }

    // 获取窗口大小
    int width, height;
    SDL_GetWindowSize(window, &width, &height);
    // 设置视口
    glViewport(0, 0, width, height);
    // 设置窗口尺寸
    _windowWidth = width;
    _windowHeight = height;

    // 游戏的初始正交投影矩阵
    _GameOrthoMatrix = glm::ortho(0.0f, (float)width / 1.2f, (float)height / 1.2f, 0.0f, -1.0f, 1.0f);
    // UI的初始正交投影矩阵
    _UIOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);

    // 设置清屏颜色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    // 启用混合模式
    glEnable(GL_BLEND);
    // 默认设置标准alpha混合
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 初始化着色器程序
    InitShaderProgram();
    // 初始化绘制2D纹理缓冲程序
    Init2DTextureProgram();

    // 设定默认使用的着色器程序和缓冲程序
    SetCurrentShaderProgram("normal");
    SetCurrentBufferObject("2DTexture");
}

RenderManager::~RenderManager()
{
    // 释放着色器程序
    for (auto &[name, program] : _shaderProgramMap)
    {
        glDeleteProgram(program);
    }
    // 释放缓冲对象
    for (auto &[name, program] : _RenderParamsMap)
    {
        glDeleteVertexArrays(1, &program.VAO);
        glDeleteBuffers(1, &program.VBO);
        glDeleteBuffers(1, &program.EBO);
    }
    // 释放OpenGL上下文
    SDL_GL_DeleteContext(_ctx);
}

void RenderManager::InitShaderProgram()
{
    std::ifstream shaderFile("shader/config.json");

    nlohmann::json shaderConfig;
    shaderFile >> shaderConfig;

    for (auto &[groupName, groupData] : shaderConfig["shader"].items())
    {
        if (!groupData.is_object())
        {
            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误，跳过\n", groupName.c_str());
            continue;
        }
        if (!groupData.contains("vertex") || !groupData["vertex"].is_string())
        {
            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 vertex 路径，跳过\n", groupName.c_str());
            continue;
        }
        if (!groupData.contains("fragment") || !groupData["fragment"].is_string())
        {
            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 fragment 路径，跳过\n", groupName.c_str());
            continue;
        }
        std::string vertPath = groupData["vertex"].get<std::string>();
        std::string fragPath = groupData["fragment"].get<std::string>();

        GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertPath);
        GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath);
        if (vertexShader == 0 || fragmentShader == 0)
        {
            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器编译失败，跳过\n", groupName.c_str());
            continue;
        }

        GLuint program = glCreateProgram();
        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        glLinkProgram(program);
        GLint programLinksuccess;
        glGetProgramiv(program, GL_LINK_STATUS, &programLinksuccess);
        if (!programLinksuccess)
        {
            char infoLog[512];
            glGetProgramInfoLog(program, 512, nullptr, infoLog);
            SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器链接失败，失败原因: %s\n", groupName.c_str(), infoLog);
        }

        _shaderProgramMap[groupName] = program;
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    }
}

void RenderManager::Init2DTextureProgram()
{
    // 初始化顶点数据（矩形的四个顶点）
    float vertices[] = {
        0.0f, 0.0f, 0.0f, 0.0f, // 左下（单位坐标）
        1.0f, 0.0f, 1.0f, 0.0f, // 右下
        1.0f, 1.0f, 1.0f, 1.0f, // 右上
        0.0f, 1.0f, 0.0f, 1.0f  // 左上
    };
    // 索引数组
    unsigned int indices[] = {0, 1, 2, 2, 3, 0};
    GLuint VAO, VBO, EBO;
    // 创建VAO/VBO/EBO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // 创建完解绑
    glBindVertexArray(0);

    SetCurrentShaderProgram("normal");
    glUseProgram(_currentShaderProgram);

    // 获取uniform变量位置
    GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
    GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
    GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
    if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无法获取着色器 uniform 变量位置\n");
    }
    std::vector<GLuint> uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc};

    DrawLogicFunc drawFunc = [this](
                                 RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
    {
        GLuint texture = textureObj->getID();
        if (!texture || !dstrect)
            return;

        glUseProgram(_currentShaderProgram);

        glm::mat4 model = glm::mat4(1.0f);

        // 平移
        model = glm::translate(model, glm::vec3(dstrect->x, dstrect->y, 0.0f));

        // 计算旋转中心
        float centerX = center ? center->x : dstrect->w * 0.5f;
        float centerY = center ? center->y : dstrect->h * 0.5f;

        // 旋转中心平移
        model = glm::translate(model, glm::vec3(centerX, centerY, 0.0f));

        // 旋转
        if (angle != 0.0)
        {
            model = glm::rotate(model, glm::radians(static_cast<float>(angle)), glm::vec3(0.0f, 0.0f, 1.0f));
        }

        // 旋转中心平移
        model = glm::translate(model, glm::vec3(-centerX, -centerY, 0.0f));

        // 缩放和翻转
        float scaleX = dstrect->w;
        float scaleY = dstrect->h;

        // 应用翻转（通过负缩放实现）
        if (flip & SDL_FLIP_HORIZONTAL)
            scaleX = -scaleX;
        if (flip & SDL_FLIP_VERTICAL)
            scaleY = -scaleY;

        model = glm::scale(model, glm::vec3(scaleX, scaleY, 1.0f));

        // 翻转后的位置补偿
        if (flip & SDL_FLIP_HORIZONTAL)
        {
            model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 0.0f));
        }
        if (flip & SDL_FLIP_VERTICAL)
        {
            model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0f));
        }

        // 设置着色器 uniforms
        glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_OrthoMatrix));

        // 绑定纹理并设置采样器
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        glUniform1i(_currentRenderParams.UnimLocs[2], 0);

        // 处理纹理裁剪
        int texWidth = textureObj->getSize().width;
        int texHeight = textureObj->getSize().height;

        // 计算纹理坐标
        float minu, minv, maxu, maxv;
        if (srcrect)
        {
            minu = (float)srcrect->x / texWidth;
            minv = (float)srcrect->y / texHeight;
            maxu = (float)(srcrect->x + srcrect->w) / texWidth;
            maxv = (float)(srcrect->y + srcrect->h) / texHeight;
        }
        else
        {
            minu = 0.0f;
            minv = 0.0f;
            maxu = 1.0f;
            maxv = 1.0f;
        }

        // 计算顶点位置（单位矩形，通过模型变换进行缩放和平移）
        float minx = 0.0f;
        float miny = 0.0f;
        float maxx = 1.0f;
        float maxy = 1.0f;

        // 创建顶点数据（位置 + 纹理坐标）
        float vertices[] = {
            // 位置     // 纹理坐标
            minx, miny, minu, minv, // 左上
            maxx, miny, maxu, minv, // 右上
            maxx, maxy, maxu, maxv, // 右下
            minx, maxy, minu, maxv  // 左下
        };

        // 更新VBO数据
        glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);

        // 绘制纹理
        glBindVertexArray(_currentRenderParams.VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    };

    GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, drawFunc};
    AddBufferObject("2DTexture", bufferObject);
}

void RenderManager::SetCurrentShaderProgram(std::string name)
{
    if (_shaderProgramMap.find(name) != _shaderProgramMap.end())
    {
        this->_currentShaderProgram = _shaderProgramMap[name];
    }
    else
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到着色器程序: %s\n", name.c_str());
}

void RenderManager::SetCurrentBufferObject(std::string name)
{
    if (_RenderParamsMap.find(name) != _RenderParamsMap.end())
    {
        this->_currentRenderParams = _RenderParamsMap[name];
    }
    else
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str());
}

void RenderManager::ClearScreen()
{
    glClear(GL_COLOR_BUFFER_BIT);
    _frameRenderCount = 0;
}

void RenderManager::SwapBuffer()
{
    SDL_GL_SwapWindow(_window);
}

void RenderManager::SetClipRect(const SDL_Rect *rect)
{
    glEnable(GL_SCISSOR_TEST);
    glScissor(rect->x, _windowHeight - rect->y - rect->h, rect->w, rect->h);
}

void RenderManager::CloseClipRect()
{
    glDisable(GL_SCISSOR_TEST);
}

void RenderManager::DrawTexture(RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
{
    _frameRenderCount++;
    if (_currentRenderParams.DrawFunc != nullptr)
        _currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata);
    else
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染逻辑函数\n");
}

void RenderManager::SetOrthoMatrixType(int type)
{
    if (type == 0)
        _OrthoMatrix = _GameOrthoMatrix;
    else
        _OrthoMatrix = _UIOrthoMatrix;
}

GLuint RenderManager::CompileShader(GLenum type, std::string Path)
{
    std::ifstream Source("shader/" + Path);
    if (!Source.is_open())
    {
        SDL_LogError(0, "Failed to open shader file: %s\n", Path.c_str());
        return 0;
    }

    std::string ShaderSource((std::istreambuf_iterator<char>(Source)), std::istreambuf_iterator<char>());
    const char *SourcePtr = ShaderSource.c_str();

    GLuint ShaderId = glCreateShader(type);
    glShaderSource(ShaderId, 1, &SourcePtr, NULL);
    glCompileShader(ShaderId);

    // 检查编译错误
    GLint success;
    glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        char infoLog[512];
        glGetShaderInfoLog(ShaderId, 512, nullptr, infoLog);
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Shader compile error: %s\n", infoLog);
        glDeleteShader(ShaderId);
        return 0;
    }
    return ShaderId;
}

void RenderManager::AddBufferObject(std::string name, GL_RenderParams bufferObject)
{
    _RenderParamsMap[name] = bufferObject;
}
