#include "config.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>      // strcasecmp
#include <libxml/parser.h>
#include <libxml/tree.h>

static xmlNodePtr find_child(xmlNodePtr parent, const char *name)
{
    if (!parent || !name) return NULL;

    for (xmlNodePtr n = parent->children; n; n = n->next)
    {
        if (n->type == XML_ELEMENT_NODE &&
            xmlStrcmp(n->name, BAD_CAST name) == 0)
        {
            return n;
        }
    }
    return NULL;
}

static void set_default_config(AppConfig *cfg)
{
    memset(cfg, 0, sizeof(*cfg));
    strncpy(cfg->ip, "127.0.0.1", sizeof(cfg->ip) - 1);
    cfg->ip[sizeof(cfg->ip) - 1] = '\0';
    strncpy(cfg->master_ip, "127.0.0.1", sizeof(cfg->master_ip) - 1);
    cfg->master_ip[sizeof(cfg->master_ip) - 1] = '\0';

    cfg->port        = 8888;
    cfg->log_level   = LOG_LEVEL_INFO;
    cfg->mode        = MODE_MASTER;
    cfg->master_port = 8888;
    cfg->persistence = PERSIST_NONE;
    cfg->allocator   = ALLOC_JEMALLOC;
}

/* ---- 字符串转枚举 ---- */

static void parse_log_level(const char *s, LogLevel *out)
{
    if (!s || !out) return;

    if (!strcasecmp(s, "DEBUG"))      *out = LOG_LEVEL_DEBUG;
    else if (!strcasecmp(s, "INFO"))  *out = LOG_LEVEL_INFO;
    else if (!strcasecmp(s, "ERROR")) *out = LOG_LEVEL_ERROR;
    /* 不认识就保持默认 */
}

static void parse_server_mode(const char *s, ServerMode *out)
{
    if (!s || !out) return;
    if (!strcasecmp(s, "master")) *out = MODE_MASTER;
    else if (!strcasecmp(s, "slave")) *out = MODE_SLAVE;
}

static void parse_persistence(const char *s, PersistenceType *out)
{
    if (!s || !out) return;
    if (!strcasecmp(s, "incremental")) *out = PERSIST_INCREMENTAL;
    else if (!strcasecmp(s, "none")) *out = PERSIST_NONE;
}

static void parse_allocator(const char *s, AllocatorType *out)
{
    if (!s || !out) return;
    if (!strcasecmp(s, "jemalloc")) *out = ALLOC_JEMALLOC;
    else if (!strcasecmp(s, "malloc")) *out = ALLOC_MALLOC;
    else *out = ALLOC_OTHER;
}

/* ---- 对外的枚举转字符串工具 ---- */

const char *log_level_to_string(LogLevel lvl)
{
    switch (lvl) {
    case LOG_LEVEL_DEBUG: return "DEBUG";
    case LOG_LEVEL_INFO:  return "INFO";
    case LOG_LEVEL_ERROR: return "ERROR";
    default:              return "UNKNOWN";
    }
}

const char *server_mode_to_string(ServerMode mode)
{
    switch (mode) {
    case MODE_MASTER: return "master";
    case MODE_SLAVE:  return "slave";
    default:          return "unknown";
    }
}

const char *persistence_to_string(PersistenceType p)
{
    switch (p) {
    case PERSIST_INCREMENTAL: return "incremental";
    case PERSIST_NONE:        return "none";
    default:                  return "unknown";
    }
}

const char *allocator_to_string(AllocatorType a)
{
    switch (a) {
    case ALLOC_JEMALLOC: return "jemalloc";
    case ALLOC_MALLOC:   return "malloc";
    case ALLOC_OTHER:    return "other";
    default:             return "unknown";
    }
}

/* ---- 主函数：从 XML 加载配置 ---- */

int config_load(const char *filename, AppConfig *out_cfg)
{
    if (!filename || !out_cfg) return -1;

    set_default_config(out_cfg);

    xmlDocPtr doc = xmlReadFile(filename, "UTF-8", XML_PARSE_NOBLANKS);
    if (!doc) {
        fprintf(stderr, "config_load: failed to read file %s\n", filename);
        return -1;
    }

    xmlNodePtr root = xmlDocGetRootElement(doc);
    if (!root || xmlStrcmp(root->name, BAD_CAST "config") != 0) {
        fprintf(stderr, "config_load: root element is not <config>\n");
        xmlFreeDoc(doc);
        return -1;
    }

    /* server 部分 */
    xmlNodePtr server = find_child(root, "server");
    if (server) {
        /* ip */
        xmlNodePtr ip_node = find_child(server, "ip");
        if (ip_node) {
            xmlChar *txt = xmlNodeGetContent(ip_node);
            if (txt) {
                strncpy(out_cfg->ip, (char *)txt, sizeof(out_cfg->ip) - 1);
                out_cfg->ip[sizeof(out_cfg->ip) - 1] = '\0';
                xmlFree(txt);
            }
        }

        /* port */
        xmlNodePtr port_node = find_child(server, "port");
        if (port_node) {
            xmlChar *txt = xmlNodeGetContent(port_node);
            if (txt) {
                out_cfg->port = atoi((char *)txt);
                xmlFree(txt);
            }
        }

        /* mode: master / slave */
        xmlNodePtr mode_node = find_child(server, "mode");
        if (mode_node) {
            xmlChar *txt = xmlNodeGetContent(mode_node);
            if (txt) {
                parse_server_mode((char *)txt, &out_cfg->mode);
                xmlFree(txt);
            }
        }

        /* master (always read if present) */
        xmlNodePtr master = find_child(server, "master");
        if (master) {
            xmlNodePtr mip_node = find_child(master, "ip");
            if (mip_node) {
                xmlChar *txt = xmlNodeGetContent(mip_node);
                if (txt) {
                    strncpy(out_cfg->master_ip, (char *)txt, sizeof(out_cfg->master_ip) - 1);
                    out_cfg->master_ip[sizeof(out_cfg->master_ip) - 1] = '\0';
                    xmlFree(txt);
                }
            }

            xmlNodePtr mport_node = find_child(master, "port");
            if (mport_node) {
                xmlChar *txt = xmlNodeGetContent(port_node);
                if (txt) {
                    out_cfg->master_port = atoi((char *)txt);
                    xmlFree(txt);
                }
            }
        }
    }

    /* log 部分 */
    xmlNodePtr log = find_child(root, "log");
    if (log) {
        xmlNodePtr lvl_node = find_child(log, "level");
        if (lvl_node) {
            xmlChar *txt = xmlNodeGetContent(lvl_node);
            if (txt) {
                parse_log_level((char *)txt, &out_cfg->log_level);
                xmlFree(txt);
            }
        }
    }

    /* persistence 部分 */
    xmlNodePtr pers = find_child(root, "persistence");
    if (pers) {
        xmlNodePtr type_node = find_child(pers, "type");
        if (type_node) {
            xmlChar *txt = xmlNodeGetContent(type_node);
            if (txt) {
                parse_persistence((char *)txt, &out_cfg->persistence);
                xmlFree(txt);
            }
        }
    }

    /* memory 部分 */
    xmlNodePtr mem = find_child(root, "memory");
    if (mem) {
        xmlNodePtr alloc_node = find_child(mem, "allocator");
        if (alloc_node) {
            xmlChar *txt = xmlNodeGetContent(alloc_node);
            if (txt) {
                parse_allocator((char *)txt, &out_cfg->allocator);
                xmlFree(txt);
            }
        }
    }

    xmlFreeDoc(doc);
    /* xmlCleanupParser() 建议在程序退出时 main 里统一调用 */

    return 0;
}
