#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include "shader.h"
#include <assert.h>

void compileShader(const GLchar *shaderSource, Shader *shader) {
    assert(shaderSource != NULL);
    assert(shader != NULL);

    shader->id = glCreateShader(shader->type);

    glShaderSource(shader->id, 1, &shaderSource, NULL);

    glCompileShader(shader->id);

    GLint status;
    glGetShaderiv(shader->id, GL_COMPILE_STATUS, &status);

    if (!status) {
        printf("Error compiling shader: ");
        GLchar infoLog[1024];
        glGetShaderInfoLog(shader->id, 1024, NULL, infoLog);
        printf("%s\n", infoLog);
        exit(1);
    }
}

void compileShaders(Shader* shaders, const GLchar** glslSources, int numShaders) {
    assert(glslSources != NULL);
    assert(shaders != NULL);
    for (int i = 0; i < numShaders; i++) {
        compileShader(glslSources[i], &shaders[i]);
    }
}

ShaderProgram createShaderProgram(const GLchar* vertexSource, const GLchar* fragmentSource) {
    assert(vertexSource != NULL);
    assert(fragmentSource != NULL);
    
    Shader vertexShader = { GL_VERTEX_SHADER, 0 };
    Shader fragmentShader = { GL_FRAGMENT_SHADER, 0 };

    const GLchar* shaderSources[2] = { vertexSource, fragmentSource };
    Shader shaders[2] = { vertexShader, fragmentShader };

    compileShaders(shaders, shaderSources, 2);

    GLuint program = glCreateProgram();
    glAttachShader(program, shaders[0].id);
    glAttachShader(program, shaders[1].id);
    glLinkProgram(program);

    GLint status;
    glGetProgramiv(program, GL_LINK_STATUS, &status);

    if (!status) {
        printf("Error linking program: ");
        GLchar infoLog[1024];
        glGetProgramInfoLog(program, 1024, NULL, infoLog);
        printf("%s\n", infoLog);
        exit(1);
    }
    
    glValidateProgram(program);

    glGetProgramiv(program, GL_VALIDATE_STATUS, &status);

    if (!status) {
        printf("Error validating program: ");
        GLchar infoLog[1024];
        glGetProgramInfoLog(program, 1024, NULL, infoLog);
        printf("%s\n", infoLog);
        exit(1);
    }

    ShaderProgram shaderProgram = { program, vertexSource, fragmentSource };
    return shaderProgram;
}
