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

#include <mongoose.h>
#include <router.h>
#include <logger.h>
#include <config.h>
#include <database.h>
#include <handlers.h>
#include <enums.h>
#include <helpers.h>
#include <confini.h>
#include <models/controller.h>

static struct mg_mgr mgr;

static void
terminate(int signum)
{
    LOG_INFO("terminating controller (%d)\n", signum);

    mg_mgr_free(&mgr);

    sqlite3_close(global_database);

    router_free();

    exit(signum);
}

/**
 * @brief The main function
 *
 * @param argc UNUSED
 * @param argv UNUSED
 *
 * @return Statuscode to indicate success (0) or failure (!0)
 */
int
main(int argc, const char** argv)
{
    signal(SIGINT, terminate);
    signal(SIGABRT, terminate);
    signal(SIGTERM, terminate);


    /******************** LOAD CONFIG ********************/

    global_config.file = "core.ini";
    strcpy(global_config.not_found_file, "404.html");
    strcpy(global_config.not_found_file_type, "text/html");
    strcpy(global_config.not_found_content, "404 - NOT FOUND");
    strcpy(global_config.not_found_content_type, "text/plain");
    global_config.log_level = LOG_LEVEL_INFO;

    helper_parse_cli(argc, argv, &global_config);

    FILE * const ini_file = fopen(global_config.file, "rb");
    if(ini_file == NULL)
    {
        LOG_FATAL("config file '%s' was not found\n", global_config.file);
        exit(1);
    }
    if(load_ini_file( ini_file, INI_DEFAULT_FORMAT, NULL, config_load, &global_config))
    {
        LOG_FATAL("unable to parse ini file\n");
        exit(1);
    }

    fclose(ini_file);

    memset(&global_config.http_server_opts, 0, sizeof(global_config.http_server_opts));
    global_config.http_server_opts.document_root = ".";  // Serve current directory
    global_config.http_server_opts.enable_directory_listing = "no";
    global_config.http_server_opts.extra_headers = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *";


    /******************** SETUP DATABASE ********************/

    int rc = sqlite3_open(global_config.database, &global_database);

    if(rc)
    {
        LOG_FATAL("can't open database: %s\n", sqlite3_errmsg(global_database));
        return 1;
    }

    if(database_migrate())
    {
        terminate(1);
    }

    sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0);


    /******************** INIT ROUTER ********************/

    router_init();


    /******************** START MAIN LOOP ********************/

    struct mg_connection *c;

    mg_mgr_init(&mgr, NULL);
    c = mg_bind(&mgr, global_config.server_port, handler_connection);
    mg_set_protocol_http_websocket(c);

    for (;;)
    {
        mg_mgr_poll(&mgr, 1000);
    }

    terminate(0);
}