/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
#ifndef OTEL_UTILS_H
#define OTEL_UTILS_H
#include <iostream>
#include <fstream>
#include <memory>
#include "json_api.h"
#include "logging.h"
#include "parse_cfg.h"

namespace Otel {
namespace Utils {

// 从JSON对象获取字符串字段
static bool GetStringField(Json* obj, const char* field, std::string& output) {
    Json* item = nullptr;
    char* value = nullptr;
    if (JsonObjectItemGet(obj, field, &item) != JSON_OK || item == nullptr) {
        debug_log(DLOG_ERROR, "%s: Missing field '%s'", __FUNCTION__, field);
        return false;
    }
    
    if (JsonItemStringValueGet(item, &value) != JSON_OK || value == nullptr) {
        debug_log(DLOG_ERROR, "%s: Invalid value for field '%s'", __FUNCTION__, field);
        return false;
    }
    output = value;
    return true;
}

// 获取JSON数组
static bool GetJsonArray(Json* obj, const char* field, Json** array) {
    if (JsonObjectItemGet(obj, field, array) != JSON_OK || !JsonIsArray(*array)) {
        debug_log(DLOG_ERROR, "%s: Missing or invalid array '%s'", __FUNCTION__, field);
        return false;
    }
    return true;
}

// 解析属性项
static void parseAttributeItem(Metric &metric, Json *attrs) {
    if (!JsonIsArray(attrs)) {
        debug_log(DLOG_ERROR, "%s: Expected array for attributes", __FUNCTION__);
        return;
    }

    uint32_t len = 0;
    if (JsonArraySizeGet(attrs, &len) != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: Failed to get array size", __FUNCTION__);
        return;
    }

    for (size_t j = 0; j < len; j++) {
        Json* attrItem = nullptr;
        if (JsonArrayItemGet(attrs, j, &attrItem) != JSON_OK || attrItem == nullptr) {
            debug_log(DLOG_ERROR, "%s: Failed to get array item %zu", __FUNCTION__, j);
            continue;
        }

        Attribute attribute;
        GetStringField(attrItem, "name", attribute.name);
        GetStringField(attrItem, "description", attribute.description);
        GetStringField(attrItem, "type", attribute.type);
        GetStringField(attrItem, "level", attribute.level);
        metric.attributes[attribute.name] =std::move(attribute);
    }
}

// 解析指标项
static void parseMetricsItem(std::map<std::string, Metric> &metrics, Json *array) {
    if (!JsonIsArray(array)) {
        debug_log(DLOG_ERROR, "%s: 'metrics' is not an array", __FUNCTION__);
        return;
    }

    uint32_t len = 0;
    if (JsonArraySizeGet(array, &len) != JSON_OK) {
        debug_log(DLOG_ERROR, "%s: Failed to get array size", __FUNCTION__);
        return;
    }

    for (size_t i = 0; i < len; i++) {
        Json* item = nullptr;
        if (JsonArrayItemGet(array, i, &item) != JSON_OK || item == nullptr) {
            debug_log(DLOG_ERROR, "%s: Failed to get metric item %zu", __FUNCTION__, i);
            continue;
        }

        Metric metric;
        GetStringField(item, "name", metric.name);
        GetStringField(item, "description", metric.description);
        GetStringField(item, "unit", metric.unit);
        GetStringField(item, "type", metric.type);

        debug_log(DLOG_DEBUG, "metric.name: %s", metric.name.c_str());

        // 解析属性数组
        Json* attrs = nullptr;
        if (GetJsonArray(item, "attributes", &attrs)) {
            parseAttributeItem(metric, attrs);
        }

        metrics[metric.name] = std::move(metric);
    }
}

// 解析JSON数据
std::map<std::string, Metric> parseMetrics(const char *path) {
    std::map<std::string, Metric> metrics;
    JsonErrorInfo *error = JsonErrorInfoCreate();
    Json *root = nullptr;
    uint32_t ret = JsonParseFile(path, &root, error);
    if (ret != JSON_OK) {
        debug_log(DLOG_ERROR, "parse config failed, err: %s", JsonErrorPtrGetMulti(error));
        JsonErrorInfoDelete(error);
        return metrics;
    }
    JsonErrorInfoDelete(error);
    
    Json *metricsArray = nullptr;
    if (GetJsonArray(root, "metrics", &metricsArray)) {
        parseMetricsItem(metrics, metricsArray);
    } else {
        debug_log(DLOG_ERROR, "No valid 'metrics' array found in config");
    }
    JsonObjectRelease(root);
    return metrics;
}

} // namespace Utils
} // namespace Otel

#endif // OTEL_UTILS_H