#include <stdio.h>
#include <stdlib.h>

#include "graphics.h"

#include "../deps/include/glad/glad.h"

const char * defaultVertexShader =
"#version 330 core\n"
"precision mediump float;"
"void main()\n"
"{\n"
"}";

const char * defaultFragmentShader =
"#version 330 core\n"
"precision mediump float;"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"    FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n"
"}";

void compileShader(GLuint program, const char * source, GLenum type) {
    GLint status = 0;

    GLuint shader = glCreateShader(type);

    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

    if (status != GL_TRUE) {
        fprintf(stderr, "Failed to compile %s shader!\n", type == GL_VERTEX_SHADER ? "vertex" : "fragment");

        GLint len;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
        char * infolog = (char*) malloc(len * sizeof(char));
        glGetShaderInfoLog(shader, len, NULL, infolog);
        fprintf(stderr, "Shader compilation error: %s\n", infolog);
        free(infolog);

        exit(1);
    }

    glAttachShader(program, shader);
}

void linkProgram(GLuint program) {
    int status = 0;

    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status != GL_TRUE) {
        fprintf(stderr, "Failed to link program!\n");

        GLint len;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
        char * infolog = (char*) malloc(len * sizeof(char));
        glGetProgramInfoLog(program, len, NULL, infolog);
        fprintf(stderr, "Program linking error: %s", infolog);
        free(infolog);

        exit(1);
    }
}

Graphics createGraphics(const char * vss, const char * fss) {
    GLuint program = glCreateProgram();

    if (vss == NULL) vss = defaultVertexShader;
    if (fss == NULL) fss = defaultFragmentShader;

    compileShader(program, vss, GL_VERTEX_SHADER);
    compileShader(program, fss, GL_FRAGMENT_SHADER);

    linkProgram(program);

    GLuint vao;
    glGenVertexArrays(1, &vao);

    return (Graphics) {
        .program = program,
        .vao = vao,
    };
}
