#include <shaders.h>
#include <opengl.h>
#include <vector>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <fstream>

uint32_t compile_shader(const char* path, int32_t type) {
    std::ifstream file(path);
    std::string source((std::istreambuf_iterator<char>(file)),
                 std::istreambuf_iterator<char>());
    const char* source_cstr = source.c_str();

    uint32_t id = compile_shader_text(path, source_cstr, type);

    return id;
}

uint32_t compile_shader_text(const char* name, const char* text, int32_t type) {
    uint32_t id = glCreateShader(type);
    glShaderSource(id, 1, &text, NULL);
    glCompileShader(id);

    int success;
    char info_log[512];
    glGetShaderiv(id, GL_COMPILE_STATUS, &success);
    if(!success) {
        glGetShaderInfoLog(id, 512, NULL, info_log);
        printf("[Shader %d, %s] Failed to compile: %s\n", id, name, info_log);
        exit(-1);
    } else {
        printf("[Shader %d, %s] Compiled successfully\n", id, name);
    }

    return id;
}


uint32_t load_shader_program(uint32_t shader, ...) {
    std::vector<uint32_t> shaders;

    va_list args;
    va_start(args, shader);
    while(shader != 0) {
        shaders.push_back(shader);
        shader = va_arg(args, uint32_t);
    }
    va_end(args);

    uint32_t program = glCreateProgram();
    for(const auto& shader : shaders) {
        glAttachShader(program, shader);
        printf("[Shader %d] Attached to program %d\n", shader, program);
    }
    glLinkProgram(program);

    int success;
    char info_log[512];
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if(!success) {
        glGetProgramInfoLog(program, 512, NULL, info_log);
        printf("[Program %d] Failed to link: %s\n", program, info_log);
        exit(-1);
    } else {
        printf("[Program %d] Linked successfully\n", program);
    }

    for(const auto& shader : shaders) {
        glDeleteShader(shader);
        printf("[Shader %d] Deleted successfully\n", shader);
    } 

    return program;
}
