#include <GL/gl.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>


#include "include/logger.h"
extern int _developer_log_level;

#define _MAXLOGLEN 1024
#define _MESSAGEMAXLEN (_MAXLOGLEN-100) // to be safe

char *levels[] = {"DEBUG", "INFO", "WARN", "ERROR", "CRIT"};

FILE* log_fd = NULL;

char logbuffer[_MAXLOGLEN], logmessagebuffer[_MESSAGEMAXLEN];

int logInit() {
    if (!_developer_log_level) return 0;
    log_fd = fopen("magik.log", "w");
    if (log_fd == NULL) return 1;
    setvbuf(log_fd, NULL, _IONBF, 0);
    #ifdef __WIN32
        logData(LOGLEVEL_CRIT, "Running on windows, formatted logs not supported; also kinda unsupported lmao", __FILE__, __LINE__, NULL);
    #endif
    return 0;
}



//couldn't be bothered so here i am with hard limit of 5
void logData(int level, char* fmt, char* filename, int linenumber, void* argv[]) {
    time_t logtime;
    time(&logtime);
    int argc = (argv == NULL ? 0:(int)(long)argv[0]);

    if (argc>5) argc=5; //tough luck knee grow

    long* arguments[5] = {NULL};
    for (int i = 0; i < argc; i++) {
        arguments[i] = argv[i+1];
    }
    for (int i = argc; i<5; i++) {
        arguments[i] = arguments[0];
    }
    if (level >= _developer_log_level) {
        if (argc > 0) {
            #ifndef __WIN32
                snprintf(logmessagebuffer, _MESSAGEMAXLEN, fmt, *arguments[0],*arguments[1],*arguments[2],*arguments[3],*arguments[4]);
            #else
                strcpy(logmessagebuffer, fmt);
            #endif
        } else {
            strcpy(logmessagebuffer, fmt);
        }
            
        snprintf(logbuffer, _MAXLOGLEN, "[%02d:%02d:%02d] %-5s: %s:%d: %s\n", localtime(&logtime)->tm_hour, // -5 -> longest string from levels
            localtime(&logtime)->tm_min,localtime(&logtime)->tm_sec, levels[level-1], filename, linenumber, logmessagebuffer);
        if (_developer_log_level != LOGLEVEL_NONE)    
            fputs(logbuffer, log_fd);
        write(2, logbuffer, strlen(logbuffer));
    }
}

void segmentationFaultCallback() {
    char* glfwerror;
    glfwGetError((const char**)&glfwerror);
    char* err = "#### SEGMENTATION FAULT ####\nglGetError():%d\nglfwGetError():%s\ngl debugging <3";
    int glErr = glGetError();
    logData(LOGLEVEL_CRIT,err, __FILE__, __LINE__, (void*[]) {(void*)2, &glErr, &glfwerror});
    sleep(1);
    exit(255);
}

void glfwErrorCallback(int error, const char* description) {
    logData(LOGLEVEL_ERR, (char*)description, "GLFW_Err", error, NULL);
}