// shader_utils.h
#ifndef SHADER_UTILS_H
#define SHADER_UTILS_H

#include <string>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h>
#else
#include <GL/glew.h>
#include <SDL_opengl.h>
#endif


GLuint LoadShaderProgram(const std::string& vsSource, const std::string& fsSource);
GLuint LoadShaderProgramFromFiles(const std::string& vsPath, const std::string& fsPath);

#endif // SHADER_UTILS_H

#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>

// Function to compile a shader
GLuint CompileShader(GLenum type, const std::string& source) {
    GLuint shader = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(shader, 1, &src, nullptr);
    glCompileShader(shader);

    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        GLint logLength;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
        std::vector<char> log(logLength);
        glGetShaderInfoLog(shader, logLength, nullptr, log.data());
        std::cerr << "ERROR::SHADER::COMPILATION_FAILED\n" << (type == GL_VERTEX_SHADER ? "Vertex" : "Fragment") << "\n" << log.data() << std::endl;
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

// Function to link shaders into a program
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader) {
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    GLint success;
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        GLint logLength;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
        std::vector<char> log(logLength);
        glGetProgramInfoLog(program, logLength, nullptr, log.data());
        std::cerr << "ERROR::PROGRAM::LINKING_FAILED\n" << log.data() << std::endl;
        glDeleteProgram(program);
        return 0;
    }
    return program;
}


GLuint LoadShaderProgram(const std::string& vsSource, const std::string& fsSource) {
    GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
    if (!vs) return 0;
    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
    if (!fs) { glDeleteShader(vs); return 0; }

    GLuint program = LinkProgram(vs, fs);

    // Shaders can be deleted after linking
    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}


std::string ReadFile(const std::string& path) {
    std::ifstream file(path);
    if (!file) {
        std::cerr << "Error opening file: " << path << std::endl;
        return "";
    }
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

GLuint LoadShaderProgramFromFiles(const std::string& vsPath, const std::string& fsPath) {
     std::string vsSource = ReadFile(vsPath);
     std::string fsSource = ReadFile(fsPath);
     if (vsSource.empty() || fsSource.empty()) {
         return 0;
     }
     return LoadShaderProgram(vsSource, fsSource);
}