/* 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.
 */
#include <mutex>

#include "common/custom_log_handler.h"
#include "utils.h"
#include <unistd.h>
#include <cstdio>
#include <string>
namespace Otel {
namespace Utils {

void get_attributes(lua_State *L, AttributeMap &attributes, int table_idx)
{
    if (!lua_istable(L, table_idx)) {
        luaL_error(L, "invalid parameter, get attributes failed");
    }
    lua_pushnil(L);
    while (lua_next(L, table_idx) != 0) {
        if (!lua_isstring(L, -2)) {
            luaL_error(L, "attribute key must be string");
        }
        const char *key = lua_tostring(L, -2);
        AttributeValue value = get_attribute_value(L, -1);
        attributes.emplace(key, value);
        lua_pop(L, 1);
    }
}

AttributeValue get_attribute_value(lua_State *L, int val_idx)
{
    AttributeValue value;
    int type = lua_type(L, val_idx);
    if (type == LUA_TNUMBER) {
        if (lua_isinteger(L, val_idx)) {
            value = static_cast<int64_t>(lua_tointeger(L, val_idx));
        } else {
            value = static_cast<double>(lua_tonumber(L, val_idx));
        }
    } else if (type == LUA_TSTRING) {
        size_t len = 0;
        const char* str = lua_tolstring(L, val_idx, &len);
        return AttributeValue(nostd::string_view(str, len));
    } else if (type == LUA_TBOOLEAN) {
        value = static_cast<bool>(lua_toboolean(L, val_idx));
    } else {
        luaL_error(L, "%s: unsupported attribute value type", __FUNCTION__);
    }

    return value;
}

void initialize_telemetry()
{
    static std::once_flag init_flag;
    std::call_once(init_flag, []() {
        // 设置日志模块
        auto cust_log_handler = new Common::CustomLogHandler{};
        cust_log_handler->SetModuleName(get_log_module_name());
        auto log_handler = nostd::shared_ptr<internal_log::LogHandler>(cust_log_handler);
        internal_log::GlobalLogHandler::SetLogHandler(log_handler);
        // 设置服务名
        std::string attr = "service.name=";
        attr.append(get_log_module_name());
        setenv("OTEL_RESOURCE_ATTRIBUTES", attr.c_str(), 1);
    });
}

static uint8_t toHexValue(char c)
{
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else if (c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    } else if (c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    } else {
        return 0xFF;
    }
}

std::vector<uint8_t> HexToBytes(const nostd::string_view &hex)
{
    std::vector<uint8_t> bytes;
    size_t len = hex.length();
    if (len % 2 != 0) {
        // 长度非偶
        return {};
    }
    bytes.reserve(len / 2);
    for (size_t i = 0; i < len; i += 2) {
        uint8_t high = toHexValue(hex.data()[i]);
        uint8_t low = toHexValue(hex.data()[i + 1]);

        if (high == 0xFF || low == 0xFF) {
            // 非法字符
            return {};
        }
        
        bytes.push_back((high << 4) | low);
    }
    return bytes;
}

#if defined(BUILD_TYPE) && defined(BUILD_TYPE_DT) && BUILD_TYPE == BUILD_TYPE_DT
// 获取当前工作目录，如果最后一级不是unit，则拼接上/test/unit
std::string get_current_directory()
{
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) == nullptr) {
        return std::string(".");
    }
    
    std::string current_dir(cwd);
    
    // 提取路径的最后一级
    size_t last_slash = current_dir.find_last_of('/');
    std::string last_segment;
    if (last_slash != std::string::npos) {
        last_segment = current_dir.substr(last_slash + 1);
    } else {
        last_segment = current_dir;
    }
    
    // 如果最后一级不是unit，拼接上/test/unit
    if (last_segment != "unit") {
        return current_dir + "/test/unit";
    }
    
    return current_dir;
}
#endif

} // namespace Utils
} // namespace Otel