// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef DYN_CONF_H
#define DYN_CONF_H

#include "../libnetdata.h"

enum module_type {
    MOD_TYPE_UNKNOWN = 0,
    MOD_TYPE_ARRAY,
    MOD_TYPE_SINGLE
};

static inline enum module_type str2_module_type(const char *type_name)
{
    if (strcmp(type_name, "job_array") == 0)
        return MOD_TYPE_ARRAY;
    else if (strcmp(type_name, "single") == 0)
        return MOD_TYPE_SINGLE;
    return MOD_TYPE_UNKNOWN;
}

struct dyncfg_config {
    void *data;
    size_t data_size;
};

typedef struct dyncfg_config dyncfg_config_t;

struct configurable_plugin;
struct module;

enum job_status {
    JOB_STATUS_UNKNOWN = 0, // State used until plugin reports first status
    JOB_STATUS_STOPPED,
    JOB_STATUS_RUNNING,
    JOB_STATUS_ERROR
};

inline enum job_status str2job_state(const char *state_name) {
    if (strcmp(state_name, "stopped") == 0)
        return JOB_STATUS_STOPPED;
    else if (strcmp(state_name, "running") == 0)
        return JOB_STATUS_RUNNING;
    else if (strcmp(state_name, "error") == 0)
        return JOB_STATUS_ERROR;
    return JOB_STATUS_UNKNOWN;
}

enum set_config_result {
    SET_CONFIG_ACCEPTED = 0,
    SET_CONFIG_REJECTED,
    SET_CONFIG_DEFFER
};

struct job
{
    char *name;

    //state reported by config
    enum job_status status; // reported by plugin, enum as this has to be interpreted by UI
    int state; // code reported by plugin which can mean anything plugin wants
    char *reason; // reported by plugin, can be NULL (optional)

    usec_t last_state_update;

    struct module *module;
};

struct module
{
    pthread_mutex_t lock;
    char *name;
    enum module_type type;

    struct configurable_plugin *plugin;

    // module config
    enum set_config_result (*set_config_cb)(void *usr_ctx, const char *module_name, dyncfg_config_t *cfg);
    dyncfg_config_t (*get_config_cb)(void *usr_ctx, const char *name);
    dyncfg_config_t (*get_config_schema_cb)(void *usr_ctx, const char *name);
    void *config_cb_usr_ctx;

    DICTIONARY *jobs;

    // jobs config
    dyncfg_config_t (*get_job_config_cb)(void *usr_ctx, const char *module_name, const char *job_name);
    dyncfg_config_t (*get_job_config_schema_cb)(void *usr_ctx, const char *module_name);
    enum set_config_result (*set_job_config_cb)(void *usr_ctx, const char *module_name, const char *job_name, dyncfg_config_t *cfg);
    enum set_config_result (*delete_job_cb)(void *usr_ctx, const char *module_name, const char *job_name);
    void *job_config_cb_usr_ctx;
};

struct configurable_plugin {
    pthread_mutex_t lock;
    char *name;
    DICTIONARY *modules;
    const char *schema;

    dyncfg_config_t (*get_config_cb)(void *usr_ctx);
    dyncfg_config_t (*get_config_schema_cb)(void *usr_ctx);
    enum set_config_result (*set_config_cb)(void *usr_ctx, dyncfg_config_t *cfg);
    void *cb_usr_ctx; // context for all callbacks (split if needed in future)
};

// API to be used by plugins
const DICTIONARY_ITEM *register_plugin(struct configurable_plugin *plugin);
void unregister_plugin(const DICTIONARY_ITEM *plugin);
int register_module(struct configurable_plugin *plugin, struct module *module);

void report_job_status(struct configurable_plugin *plugin, const char *module_name, const char *job_name, enum job_status status, int status_code, char *reason);

// API to be used by the web server(s)
json_object *get_list_of_plugins_json();
struct configurable_plugin *get_plugin_by_name(const char *name);

json_object *get_list_of_modules_json(struct configurable_plugin *plugin);
struct module *get_module_by_name(struct configurable_plugin *plugin, const char *module_name);

// helper struct to make interface between internal webserver and h2o same
struct uni_http_response {
    int status;
    char *content;
    size_t content_length;
    HTTP_CONTENT_TYPE content_type;
    void (*content_free)(void *);
};

struct uni_http_response dyn_conf_process_http_request(int method, const char *plugin, const char *module, const char *job_id, void *payload, size_t payload_size);

// API to be used by main netdata process, initialization and destruction etc.
int dyn_conf_init(void);
void freez_dyncfg(void *ptr);
void *dyncfg_main(void *in);

#endif //DYN_CONF_H
