#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "toml.h"
#include "log_private.h"
#include "stellar_config.h"

#define CONFIG_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "config", format, ##__VA_ARGS__)
#define CONFIG_LOG_DEBUG(format, ...) STELLAR_LOG_DEBUG(__thread_local_logger, "config", format, ##__VA_ARGS__)

// return  0: success
// retuun -1: failed
static int parse_snowflake_section(toml_table_t *root, struct snowflake_options *opts)
{
    const char *ptr;
    toml_table_t *table;

    table = toml_table_in(root, "snowflake");
    if (table == NULL)
    {
        CONFIG_LOG_ERROR("config file missing snowflake section");
        return -1;
    }

    ptr = toml_raw_in(table, "snowflake_base");
    if (ptr == NULL)
    {
        CONFIG_LOG_ERROR("config file missing snowflake->snowflake_base");
        return -1;
    }
    opts->snowflake_base = atoi(ptr);

    ptr = toml_raw_in(table, "snowflake_offset");
    if (ptr == NULL)
    {
        CONFIG_LOG_ERROR("config file missing snowflake->snowflake_offset");
        return -1;
    }
    opts->snowflake_offset = atoi(ptr);

    return 0;
}

// return  0: success
// retuun -1: failed
static int parse_schedule_options(toml_table_t *root, struct schedule_options *opts)
{
    const char *ptr;
    toml_table_t *table;

    table = toml_table_in(root, "schedule");
    if (table == NULL)
    {
        CONFIG_LOG_ERROR("config file missing schedule section");
        return -1;
    }

    ptr = toml_raw_in(table, "merge_stat_interval");
    if (ptr == NULL)
    {
        CONFIG_LOG_ERROR("config file missing schedule->merge_stat_interval");
        return -1;
    }
    opts->merge_stat_interval = atoll(ptr);
    if (opts->merge_stat_interval < 1 || opts->merge_stat_interval > 60000)
    {
        CONFIG_LOG_ERROR("config file invalid schedule->merge_stat_interval %ld, range [1, 60000]", opts->merge_stat_interval);
        return -1;
    }

    ptr = toml_raw_in(table, "output_stat_interval");
    if (ptr == NULL)
    {
        CONFIG_LOG_ERROR("config file missing schedule->output_stat_interval");
        return -1;
    }
    opts->output_stat_interval = atoll(ptr);
    if (opts->output_stat_interval < 1 || opts->output_stat_interval > 60000)
    {
        CONFIG_LOG_ERROR("config file invalid schedule->output_stat_interval %ld, range [1, 60000]", opts->output_stat_interval);
        return -1;
    }

    return 0;
}

// return  0: success
// retuun -1: failed
int stellar_config_load(struct stellar_config *config, const char *file)
{
    int ret = -1;
    char errbuf[200];
    FILE *fp = NULL;
    toml_table_t *table = NULL;

    fp = fopen(file, "r");
    if (fp == NULL)
    {
        CONFIG_LOG_ERROR("open config file %s failed, %s", file, strerror(errno));
        goto error_out;
    }

    table = toml_parse_file(fp, errbuf, sizeof(errbuf));
    if (table == NULL)
    {
        CONFIG_LOG_ERROR("parse config file %s failed, %s", file, errbuf);
        goto error_out;
    }

    if (parse_snowflake_section(table, &config->snowflake_opts) != 0)
    {
        goto error_out;
    }

    if (parse_schedule_options(table, &config->sched_opts) != 0)
    {
        goto error_out;
    }

    ret = 0;

error_out:
    if (table)
    {
        toml_free(table);
    }

    if (fp)
    {
        fclose(fp);
    }

    return ret;
}

void stellar_config_print(const struct stellar_config *config)
{
    if (config == NULL)
    {
        return;
    }

    const struct snowflake_options *snowflake_opts = &config->snowflake_opts;

    // snowflake config
    CONFIG_LOG_DEBUG("snowflake->snowflake_base                            : %d", snowflake_opts->snowflake_base);
    CONFIG_LOG_DEBUG("snowflake->snowflake_offset                          : %d", snowflake_opts->snowflake_offset);

    // schedule config
    CONFIG_LOG_DEBUG("schedule->merge_stat_interval                        : %ld", config->sched_opts.merge_stat_interval);
    CONFIG_LOG_DEBUG("schedule->output_stat_interval                       : %ld", config->sched_opts.output_stat_interval);
}
