/**
* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* 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 FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef LOG_H
#define LOG_H

#include <dlog_pub.h>
#include <hccl/base.h>
#include <hccl/hccl_types.h>
#include <securec.h>
#include <iostream>
#include <sstream>
#include <sys/syscall.h>
#include <unistd.h>
#include <string>
#include "dlog_pub.h"
#ifndef T_DESC
#define T_DESC(_msg, _y) ((_y) ? true : false)
#endif

#if T_DESC("日志处理适配", true)

enum class HcclSubModuleID {
    LOG_SUB_MODULE_ID_HCCL = 0,
    LOG_SUB_MODULE_ID_HCOM = 1,
    LOG_SUB_MODULE_ID_CLTM = 2,
    LOG_SUB_MODULE_ID_CUSTOM_OP = 3
};

/* 设置日志的commid和rankid */
#ifndef LIKELY
#define LIKELY(x) (static_cast<bool>(__builtin_expect(static_cast<bool>(x), 1)))
#define UNLIKELY(x) (static_cast<bool>(__builtin_expect(static_cast<bool>(x), 0)))
#endif

/* 每一条日志的长度,超过该长度会申请堆内存 */
constexpr s32 LOG_TMPBUF_SIZE = 512;

#define LOG_FUNC(module, level, fmt, ...) do { \
    DlogRecord(module, level, fmt, ##__VA_ARGS__); \
} while (0)

#define ASCENDC_MC2_DLOG_MODULE (static_cast<int32_t>(ASCENDCKERNEL))
#define ASCENDC_MC2_RUN_LOG_MASK (ASCENDC_MC2_DLOG_MODULE | static_cast<int32_t>(RUN_LOG_MASK))

bool HcclCheckLogLevel(int logType, int moduleId = ASCENDC_MC2_DLOG_MODULE);

void SetErrToWarnSwitch(bool flag); // 设置True时修改日志级别:ERROR -> RUN_WARNING,设置False恢复日志级别

bool IsErrorToWarn();

#define HCCL_LOG_DEBUG DLOG_DEBUG
#define HCCL_LOG_INFO  DLOG_INFO
#define HCCL_LOG_WARN  DLOG_WARN
#define HCCL_LOG_ERROR DLOG_ERROR

#define HCCL_LOG_MASK ASCENDC_MC2_RUN_LOG_MASK

#define HCCL_LOG_PRINT(moduleId, logType, format, ...) do { \
    LOG_FUNC(moduleId, logType, "[%s:%d] [%u]" format, __FILE__, __LINE__, syscall(SYS_gettid), ##__VA_ARGS__); \
} while(0)

#define HCCL_ERROR_LOG_PRINT(format, ...) do { \
    if (IsErrorToWarn()) { \
        LOG_FUNC(ASCENDC_MC2_RUN_LOG_MASK, DLOG_WARN, "[%s:%d] [%u]ErrToWarn: " format, \
                 __FILE__, __LINE__, syscall(SYS_gettid), ##__VA_ARGS__); \
    } else { \
        LOG_FUNC(ASCENDC_MC2_DLOG_MODULE, DLOG_ERROR, "[%s:%d] [%u]" format, \
                 __FILE__, __LINE__, syscall(SYS_gettid), ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_RUN_LOG_PRINT(format, ...) do { \
    LOG_FUNC(ASCENDC_MC2_RUN_LOG_MASK, DLOG_INFO, "[%s:%d] [%u]" format, \
             __FILE__, __LINE__, syscall(SYS_gettid), ##__VA_ARGS__); \
} while(0)

// 错误码
const u64 SYSTEM_RESERVE_ERROR = 0;
const u64 HCCL_MODULE_ID = 5;

/* 预定义日志宏, 便于使用 */
#define HCCL_DEBUG(format, ...) do { \
    if (UNLIKELY(HcclCheckLogLevel(HCCL_LOG_DEBUG))) { \
        HCCL_LOG_PRINT(ASCENDC_MC2_DLOG_MODULE, HCCL_LOG_DEBUG, format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_INFO(format, ...) do { \
    if (UNLIKELY(HcclCheckLogLevel(HCCL_LOG_INFO))) { \
        HCCL_LOG_PRINT(ASCENDC_MC2_DLOG_MODULE, HCCL_LOG_INFO, format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_WARNING(format, ...) do { \
    if (UNLIKELY(HcclCheckLogLevel(HCCL_LOG_WARN))) { \
        HCCL_LOG_PRINT(ASCENDC_MC2_DLOG_MODULE, HCCL_LOG_WARN, format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_ERROR(format, ...) do { \
    if (LIKELY(HcclCheckLogLevel(HCCL_LOG_ERROR))) { \
        HCCL_ERROR_LOG_PRINT(format, ##__VA_ARGS__); \
    } \
} while(0)

/* 运行日志 */
#define HCCL_RUN_INFO(format, ...) do { \
    if (LIKELY(HcclCheckLogLevel(HCCL_LOG_INFO, HCCL_LOG_MASK))) { \
        HCCL_RUN_LOG_PRINT(format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_RUN_WARNING(format, ...) do { \
    if (LIKELY(HcclCheckLogLevel(HCCL_LOG_WARN, HCCL_LOG_MASK))) { \
        HCCL_LOG_PRINT(ASCENDC_MC2_RUN_LOG_MASK, HCCL_LOG_WARN, format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_USER_CRITICAL_LOG(format, ...) do { \
    if (LIKELY(HcclCheckLogLevel(HCCL_LOG_INFO, HCCL_LOG_MASK))) { \
        HCCL_RUN_LOG_PRINT(format, ##__VA_ARGS__); \
    } \
} while(0)

#define HCCL_ERROR_CODE(error) ((SYSTEM_RESERVE_ERROR << 32) + (HCCL_MODULE_ID << 24) + \
    ((static_cast<u64>(HcclSubModuleID::LOG_SUB_MODULE_ID_HCCL)) << 16) + static_cast<u64>(error))
#define HCOM_ERROR_CODE(error) ((SYSTEM_RESERVE_ERROR << 32) + (HCCL_MODULE_ID << 24) + \
    ((static_cast<u64>(HcclSubModuleID::LOG_SUB_MODULE_ID_HCOM)) << 16) + static_cast<u64>(error))
#endif

#if T_DESC("公共代码宏", true)

// 检查C++11的智能指针, 若为空, 则记录日志, 并返回错误
#define CHK_SMART_PTR_NULL(smart_ptr)                                                            \
    do {                                                                                                    \
        if (UNLIKELY(!(smart_ptr))) {                                                   \
            HCCL_ERROR("[%s]errNo[0x%016llx] ptr [%s] is nullptr, return HCCL_E_PTR", \
                __func__, HCCL_ERROR_CODE(HCCL_E_PTR), \
                #smart_ptr);                                                                                \
            return HCCL_E_PTR;                                                                              \
        }                                                                                                   \
    } while (0)

// 检查C++11的智能指针, 若为空, 则记录日志, 并返回
#define CHK_SMART_PTR_RET_NULL(smart_ptr)                       \
    do {                                                        \
        if (UNLIKELY(!(smart_ptr))) {                           \
            HCCL_ERROR("[%s]errNo[0x%016llx]smart_ptr is nullptr.",   \
            __func__, HCCL_ERROR_CODE(HCCL_E_PTR));                       \
            return;                                             \
        }                                                       \
    } while (0)

/* 检查指针, 若指针为NULL, 则记录日志, 并返回错误 */
#define CHK_PTR_NULL(ptr)                                                                               \
    do {                                                                                                           \
        if (UNLIKELY((ptr) == nullptr)) {                  \
            HCCL_ERROR("[%s]errNo[0x%016llx]ptr [%s] is nullptr, return HCCL_E_PTR", \
            __func__, HCCL_ERROR_CODE(HCCL_E_PTR), #ptr); \
            return HCCL_E_PTR;                                                                                     \
        }                                                                                                          \
    } while (0)

/* 检查函数返回值, 记录指定日志, 并返回指定错误码 */
#define CHK_PRT_RET(result, exeLog, retCode) \
    do {                                      \
        if (UNLIKELY(result)) {                         \
            exeLog;                           \
            return retCode;                   \
        }                                     \
    } while (0)

/* 检查函数返回值, 记录指定日志, 函数不返回 */
#define CHK_PRT_CONT(result, exeLog) \
    do {                                      \
        if (UNLIKELY(result)) {               \
            exeLog;                           \
        }                                     \
    } while (0)

/* 检查函数返回值, 并返回指定错误码 */
#define CHK_RET(call)                                 \
    do {                                              \
        HcclResult hcclRet = call;                        \
        if (UNLIKELY(hcclRet != HCCL_SUCCESS)) {                    \
            if (hcclRet == HCCL_E_AGAIN) {                \
                HCCL_WARNING("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
            } else {                                  \
                HCCL_ERROR("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
            }                                         \
            return hcclRet;                               \
        }                                             \
    } while (0)

/* 检查函数返回值, 返错时打印函数名及通信域标识 */
#define CHK_RET_AND_PRINT_IDE(call, identifier)         \
    do {                                              \
        HcclResult hcclRet = call;                        \
        if (UNLIKELY(hcclRet != HCCL_SUCCESS)) {                    \
            HCCL_RUN_INFO("[HCCL_TRACE]%s identifier[%s]", __func__, identifier); \
            if (hcclRet == HCCL_E_AGAIN) {                \
                HCCL_WARNING("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
            } else {                                  \
                HCCL_ERROR("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
            }                                         \
            return hcclRet;                               \
        }                                             \
    } while (0)

/* 检查函数返回值, 并返回空 */
#define CHK_RET_NULL(call)                                 \
    do {                                              \
        HcclResult ret = call;                        \
        if (UNLIKELY(ret != HCCL_SUCCESS)) {                    \
            if (ret == HCCL_E_AGAIN) {                \
                HCCL_WARNING("[%s]call trace: ret -> %d", __func__, ret); \
            } else {                                  \
                HCCL_ERROR("[%s]call trace: ret -> %d", __func__, ret); \
            }                                         \
            return;                               \
        }                                             \
    } while (0)

/* 检查函数返回值, 打印错误码, 函数不返回 */
#define CHK_PRT(call)                                 \
    do {                                              \
        HcclResult ret = call;                        \
        if (UNLIKELY(ret != HCCL_SUCCESS)) {                    \
            if (ret == HCCL_E_AGAIN) {                \
                HCCL_WARNING("[%s]call trace: ret -> %d", __func__, ret); \
            } else {                                  \
                HCCL_ERROR("[%s]call trace: ret -> %d", __func__, ret); \
            }                                         \
        }                                             \
    } while (0)

/* 检查函数返回值, 并返回HCCL_E_INTERNAL错误码 */
#define CHK_SAFETY_FUNC_RET(call)                                 \
    do {                                              \
        s32 ret = call;                        \
        if (UNLIKELY(ret != EOK)) {                    \
            HCCL_ERROR("[%s]call trace: safety func err ret -> %d", __func__, ret); \
            return HCCL_E_INTERNAL;                               \
        }                                             \
    } while (0)

/* 检查result. 若错误, 则设置错误并break */
#define CHK_PRT_BREAK(result, exeLog, exeCmd) \
    if (UNLIKELY(result)) {                              \
        exeLog;                                \
        exeCmd;                                \
        break;                                 \
    }

#define EXECEPTION_CATCH(expression, retExp)                     \
    do {                                                         \
        try {                                                    \
            expression;                                          \
        } catch (std::exception& e) {                            \
            HCCL_ERROR("[%s]Failed, exception caught:%s", __func__, e.what()); \
            retExp;                                              \
        }                                                        \
    } while (0)

/* 若new失败, 则捕获异常返回 */
#ifndef NEW_NOTHROW
#define NEW_NOTHROW(pointer, constructor, retExp)        \
    do {                                                 \
        pointer = new(std::nothrow) constructor;         \
        if (pointer == nullptr) {                        \
            HCCL_ERROR("[%s]Memory application failed.", __func__);     \
            retExp;                                      \
        }                                                \
    } while (0)
#endif

template <typename T>
void ArrayToStringAndPrint(T arr[], int size, const char *name)
{
    if (arr == nullptr) {
        HCCL_ERROR("Array Data, %s: data is nullptr", name);
        return;
    }

    constexpr int NUM_IN_ROW = 50;
    std::stringstream ss;
    for (int i = 0; i < size; i++) {
        ss << arr[i] << " ";
        if ((i + 1) % NUM_IN_ROW == 0) {
            HCCL_DEBUG("Array Data, %s: %s", name, ss.str().c_str());
            ss.clear();
            ss.str(std::string());
        }
    }

    HCCL_DEBUG("Array Data, %s: %s", name, ss.str().c_str());
}

#ifdef DUMP_DATA
#define PRINT_ARRAY(arr, cnt, name) \
    ArrayToStringAndPrint(arr, cnt, name)

#else
#define PRINT_ARRAY(arr, cnt, name)
#endif

#endif

#endif // LOG_H