/**
 * Copyright (c) 2025 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 ACL_COMMON_LOG_INNER_H_
#define ACL_COMMON_LOG_INNER_H_

#include <string>
#include <vector>
#include "dlog_pub.h"
#include "mmpa/mmpa_api.h"
#include "acl/acl_base_rt.h"

#ifndef char_t
using char_t = char;
#endif

#ifndef float32_t
using float32_t = float;
#endif

namespace acl {
constexpr int32_t ACL_MODE_ID = static_cast<int32_t>(ASCENDCL);
constexpr uint16_t ACL_MODE_ID_U16 = static_cast<uint16_t>(ASCENDCL);
constexpr int32_t APP_MODE_ID = static_cast<int32_t>(APP);
constexpr const char_t *const ACL_MODULE_NAME = "ASCENDCL";
constexpr const char_t *const INVALID_PARAM_MSG = "EH0001";
constexpr const char_t *const INVALID_NULL_POINTER_MSG = "EH0002";
constexpr const char_t *const INVALID_PATH_MSG = "EH0003";
constexpr const char_t *const INVALID_FILE_MSG = "EH0004";
constexpr const char_t *const INVALID_AIPP_MSG = "EH0005";
constexpr const char_t *const UNSUPPORTED_FEATURE_MSG = "EH0006";

// first stage
constexpr const char_t *const ACL_STAGE_SET = "SET";
constexpr const char_t *const ACL_STAGE_GET = "GET";
constexpr const char_t *const ACL_STAGE_CREATE = "CREATE";
constexpr const char_t *const ACL_STAGE_DESTROY = "DESTROY";
constexpr const char_t *const ACL_STAGE_INFER = "INFER";
constexpr const char_t *const ACL_STAGE_COMP = "COMP";
constexpr const char_t *const ACL_STAGE_LOAD = "LOAD";
constexpr const char_t *const ACL_STAGE_UNLOAD = "UNLOAD";
constexpr const char_t *const ACL_STAGE_EXEC = "EXEC";
constexpr const char_t *const ACL_STAGE_COMP_AND_EXEC = "COMP_AND_EXEC";
constexpr const char_t *const ACL_STAGE_DUMP = "DUMP";
constexpr const char_t *const ACL_STAGE_DVPP = "DVPP";
constexpr const char_t *const ACL_STAGE_TDT = "TDT";
constexpr const char_t *const ACL_STAGE_INIT = "INIT";
constexpr const char_t *const ACL_STAGE_FINAL = "FINAL";
constexpr const char_t *const ACL_STAGE_QUEUE = "QUEUE";
constexpr const char_t *const ACL_STAGE_MBUF = "MBUF";
constexpr const char_t *const ACL_STAGE_BLAS = "BLAS";

// second stage
constexpr const char_t *const ACL_STAGE_DEFAULT = "DEFAULT";

constexpr size_t MAX_LOG_STRING = 1024U;

constexpr size_t MAX_ERROR_STRING = 128U;

inline const char_t *format_cast(const char_t *const src) {
  return static_cast<const char_t *>(src);
}

ACL_FUNC_VISIBILITY std::string AclGetErrorFormatMessage(const mmErrorMsg errnum);

class AclLog {
 public:
  static bool IsLogOutputEnable(const aclLogLevel logLevel);
  static mmPid_t GetTid();
  static void ACLSaveLog(const aclLogLevel logLevel, const char_t *const strLog);
  static bool IsEventLogOutputEnable();

 private:
  static aclLogLevel GetCurLogLevel();
  static bool isEnableEvent_;
};

class AclErrorLogManager {
 public:
  static std::string FormatStr(const char_t *const fmt, ...);
  static void ReportInputError(const char *errorCode, const std::vector<const char *> &key = {},
                               const std::vector<const char *> &val = {});
  static void ReportInputErrorWithChar(const char_t *const errorCode, const char_t *const argNames[],
                                       const char_t *const argVals[], const size_t size);
  static void ReportInnerError(const char_t *const fmt, ...);
  static void ReportCallError(const char_t *const fmt, ...);
};
}  // namespace acl

#if defined(__GNUC__) || defined(__clang__)
#define LIKELY(expr) (static_cast<bool>(__builtin_expect(static_cast<bool>(expr), 1)))
#define UNLIKELY(expr) (static_cast<bool>(__builtin_expect(static_cast<bool>(expr), 0)))
#else
#define LIKELY(expr) (expr)
#define UNLIKELY(expr) (expr)
#endif

#ifdef RUN_TEST
#define ACL_LOG_INFO(fmt, ...)                                                                                      \
  do {                                                                                                              \
    if (acl::AclLog::IsLogOutputEnable(ACL_INFO)) {                                                                 \
      constexpr const char_t *const funcName = __FUNCTION__;                                                        \
      printf("INFO %d %s:%s:%d: " #fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
             ##__VA_ARGS__);                                                                                        \
    }                                                                                                               \
  } while (false)
#define ACL_LOG_DEBUG(fmt, ...)                                                                                      \
  do {                                                                                                               \
    if (acl::AclLog::IsLogOutputEnable(ACL_DEBUG)) {                                                                 \
      constexpr const char_t *const funcName = __FUNCTION__;                                                         \
      printf("DEBUG %d %s:%s:%d: " #fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
             ##__VA_ARGS__);                                                                                         \
    }                                                                                                                \
  } while (false)
#define ACL_LOG_WARN(fmt, ...)                                                                                      \
  do {                                                                                                              \
    if (acl::AclLog::IsLogOutputEnable(ACL_WARNING)) {                                                              \
      constexpr const char_t *const funcName = __FUNCTION__;                                                        \
      printf("WARN %d %s:%s:%d: " #fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
             ##__VA_ARGS__);                                                                                        \
    }                                                                                                               \
  } while (false)
#define ACL_LOG_ERROR(fmt, ...)                                                                                  \
  do {                                                                                                           \
    constexpr const char_t *const funcName = __FUNCTION__;                                                       \
    printf("ERROR %d %s:%s:%d:" fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
           ##__VA_ARGS__);                                                                                       \
  } while (false)
#define ACL_LOG_INNER_ERROR(fmt, ...)                                                                            \
  do {                                                                                                           \
    constexpr const char_t *const funcName = __FUNCTION__;                                                       \
    printf("ERROR %d %s:%s:%d:" fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
           ##__VA_ARGS__);                                                                                       \
  } while (false)
#define ACL_LOG_CALL_ERROR(fmt, ...)                                                                             \
  do {                                                                                                           \
    constexpr const char_t *const funcName = __FUNCTION__;                                                       \
    printf("ERROR %d %s:%s:%d:" fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
           ##__VA_ARGS__);                                                                                       \
  } while (false)
#define ACL_LOG_EVENT(fmt, ...)                                                                                      \
  do {                                                                                                               \
    if (acl::AclLog::IsEventLogOutputEnable()) {                                                                     \
      constexpr const char_t *const funcName = __FUNCTION__;                                                         \
      printf("EVENT %d %s:%s:%d: " #fmt "\n", acl::AclLog::GetTid(), acl::format_cast(funcName), __FILE__, __LINE__, \
             ##__VA_ARGS__);                                                                                         \
    }                                                                                                                \
  } while (false)
#else
#define ACL_LOG_INFO(fmt, ...)                                                                                    \
  do {                                                                                                            \
    constexpr const char_t *const funcName = __FUNCTION__;                                                        \
    dlog_info(acl::ACL_MODE_ID, "%d %s: " fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
  } while (false)
#define ACL_LOG_DEBUG(fmt, ...)                                                                                    \
  do {                                                                                                             \
    constexpr const char_t *const funcName = __FUNCTION__;                                                         \
    dlog_debug(acl::ACL_MODE_ID, "%d %s: " fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
  } while (false)
#define ACL_LOG_WARN(fmt, ...)                                                                                    \
  do {                                                                                                            \
    constexpr const char_t *const funcName = __FUNCTION__;                                                        \
    dlog_warn(acl::ACL_MODE_ID, "%d %s: " fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
  } while (false)
#define ACL_LOG_ERROR(fmt, ...)                                                                                   \
  do {                                                                                                            \
    constexpr const char_t *const funcName = __FUNCTION__;                                                        \
    dlog_error(acl::ACL_MODE_ID, "%d %s:" fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
  } while (false)
#define ACL_LOG_INNER_ERROR(fmt, ...)                                                                             \
  do {                                                                                                            \
    constexpr const char_t *const funcName = __FUNCTION__;                                                        \
    dlog_error(acl::ACL_MODE_ID, "%d %s:" fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
    acl::AclErrorLogManager::ReportInnerError((fmt), ##__VA_ARGS__);                                              \
  } while (false)
#define ACL_LOG_CALL_ERROR(fmt, ...)                                                                              \
  do {                                                                                                            \
    constexpr const char_t *const funcName = __FUNCTION__;                                                        \
    dlog_error(acl::ACL_MODE_ID, "%d %s:" fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), ##__VA_ARGS__); \
    acl::AclErrorLogManager::ReportCallError((fmt), ##__VA_ARGS__);                                               \
  } while (false)
#define ACL_LOG_EVENT(fmt, ...)                                                                                        \
  do {                                                                                                                 \
    if (acl::AclLog::IsEventLogOutputEnable()) {                                                                       \
      constexpr const char_t *const funcName = __FUNCTION__;                                                           \
      dlog_info((acl::ACL_MODE_ID | (RUN_LOG_MASK)), "%d %s: " fmt, acl::AclLog::GetTid(), acl::format_cast(funcName), \
                ##__VA_ARGS__);                                                                                        \
    }                                                                                                                  \
  } while (false)
#endif

#define OFFSET_OF_MEMBER(type, member) reinterpret_cast<size_t>(&((reinterpret_cast<type *>(0))->member))

#define ACL_REQUIRES_OK(expr)      \
  do {                             \
    const aclError __ret = (expr); \
    if (__ret != ACL_SUCCESS) {    \
      return __ret;                \
    }                              \
  } while (false)

#define ACL_REQUIRES_CALL_GE_OK(expr, ...) \
  do {                                     \
    const auto __ret = (expr);             \
    if (__ret != ge::SUCCESS) {            \
      ACL_LOG_CALL_ERROR(__VA_ARGS__);     \
      return __ret;                        \
    }                                      \
  } while (false)

#define ACL_REQUIRES_CALL_RTS_OK(expr, interface)                                                  \
  do {                                                                                             \
    const rtError_t __ret = (expr);                                                                \
    if (__ret != ACL_ERROR_NONE) {                                                                 \
      if (__ret == ACL_ERROR_RT_FEATURE_NOT_SUPPORT) {                                             \
        ACL_LOG_WARN("rts api [%s] is not supported currently,", #interface);                      \
        return __ret;                                                                              \
      }                                                                                            \
      ACL_LOG_CALL_ERROR("[Call][Rts]call rts api [%s] failed, retCode is %d", #interface, __ret); \
      return __ret;                                                                                \
    }                                                                                              \
  } while (false)

#define ACL_REQUIRES_OK_WITH_INNER_MESSAGE(expr, ...) \
  do {                                                \
    const aclError __ret = (expr);                    \
    if (__ret != ACL_SUCCESS) {                       \
      ACL_LOG_INNER_ERROR(__VA_ARGS__);               \
      return __ret;                                   \
    }                                                 \
  } while (false)

// Validate whether the expr value is true
#define ACL_REQUIRES_TRUE(expr, errCode, errDesc) \
  do {                                            \
    const bool __ret = (expr);                    \
    if (!__ret) {                                 \
      ACL_LOG_ERROR(errDesc);                     \
      return (errCode);                           \
    }                                             \
  } while (false)

#define ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(val)                          \
  do {                                                                        \
    if (UNLIKELY((val) == nullptr)) {                                         \
      ACL_LOG_ERROR("[Check][%s]param must not be null.", #val);              \
      acl::AclErrorLogManager::ReportInputError("EH0002", {"param"}, {#val}); \
      return ACL_ERROR_INVALID_PARAM;                                         \
    }                                                                         \
  } while (false)

#define ACL_REQUIRES_NOT_NULL(val)                               \
  do {                                                           \
    if (UNLIKELY((val) == nullptr)) {                            \
      ACL_LOG_ERROR("[Check][%s]param must not be null.", #val); \
      return ACL_ERROR_INVALID_PARAM;                            \
    }                                                            \
  } while (false)

#define ACL_REQUIRES_NOT_NULL_RET_NULL(val)                      \
  do {                                                           \
    if (UNLIKELY((val) == nullptr)) {                            \
      ACL_LOG_ERROR("[Check][%s]param must not be null.", #val); \
      return nullptr;                                            \
    }                                                            \
  } while (false)

#define ACL_REQUIRES_NOT_NULL_RET_NULL_INPUT_REPORT(val)                      \
  do {                                                                        \
    if (UNLIKELY((val) == nullptr)) {                                         \
      ACL_LOG_ERROR("[Check][%s]param must not be null.", #val);              \
      acl::AclErrorLogManager::ReportInputError("EH0002", {"param"}, {#val}); \
      return nullptr;                                                         \
    }                                                                         \
  } while (false)

#define ACL_REQUIRES_NOT_NULL_RET_VOID(val)                      \
  do {                                                           \
    if (UNLIKELY((val) == nullptr)) {                            \
      ACL_LOG_ERROR("[Check][%s]param must not be null.", #val); \
      return;                                                    \
    }                                                            \
  } while (false)

#define ACL_CHECK_MALLOC_RESULT(val)                                                \
  do {                                                                              \
    if ((val) == nullptr) {                                                         \
      ACL_LOG_INNER_ERROR("[Check][Malloc]Allocate memory for [%s] failed.", #val); \
      return ACL_ERROR_BAD_ALLOC;                                                   \
    }                                                                               \
  } while (false)

#define ACL_CHECK_RANGE_INT(val, min, max)                                                                        \
  do {                                                                                                            \
    if (((val) < (min)) || ((val) > (max))) {                                                                     \
      ACL_LOG_ERROR("[Check][%s]param:[%d] must be in range of [%d] and [%d]", #val, (static_cast<int32_t>(val)), \
                    (static_cast<int32_t>(min)), (static_cast<int32_t>(max)));                                    \
      return ACL_ERROR_INVALID_PARAM;                                                                             \
    }                                                                                                             \
  } while (false)

#define ACL_CHECK_RANGE_FLOAT(val, min, max)                                                                      \
  do {                                                                                                            \
    if (((val) < (min)) || ((val) > (max))) {                                                                     \
      ACL_LOG_ERROR("[Check][%s]param:[%.2f] must be in range of [%.2f] and [%.2f]", #val,                        \
                    (static_cast<float64_t>(val)), (static_cast<float64_t>(min)), (static_cast<float64_t>(max))); \
      return ACL_ERROR_INVALID_PARAM;                                                                             \
    }                                                                                                             \
  } while (false)

#define ACL_REQUIRES_NON_NEGATIVE(val)                               \
  do {                                                               \
    if ((val) < 0) {                                                 \
      ACL_LOG_ERROR("[Check][%s]param must be non-negative.", #val); \
      return ACL_ERROR_INVALID_PARAM;                                \
    }                                                                \
  } while (false)

#define ACL_REQUIRES_NON_NEGATIVE_WITH_INPUT_REPORT(val)                                           \
  do {                                                                                             \
    if ((val) < 0) {                                                                               \
      ACL_LOG_ERROR("[Check][%s]param must be non-negative.", #val);                               \
      acl::AclErrorLogManager::ReportInputError(                                                   \
          "EH0001", std::vector<const char *>({"param", "value", "reason"}),                       \
          std::vector<const char *>({#val, std::to_string(val).c_str(), "must be non-negative"})); \
      return ACL_ERROR_INVALID_PARAM;                                                              \
    }                                                                                              \
  } while (false)

#define ACL_REQUIRES_POSITIVE_WITH_INPUT_REPORT(val)                                           \
  do {                                                                                         \
    if ((val) <= 0) {                                                                          \
      ACL_LOG_ERROR("[Check][%s]param must be positive.", #val);                               \
      acl::AclErrorLogManager::ReportInputError(                                               \
          "EH0001", std::vector<const char *>({"param", "value", "reason"}),                   \
          std::vector<const char *>({#val, std::to_string(val).c_str(), "must be positive"})); \
      return ACL_ERROR_INVALID_PARAM;                                                          \
    }                                                                                          \
  } while (false)

#define ACL_REQUIRES_POSITIVE(val)                               \
  do {                                                           \
    if ((val) <= 0) {                                            \
      ACL_LOG_ERROR("[Check][%s]param must be positive.", #val); \
      return ACL_ERROR_INVALID_PARAM;                            \
    }                                                            \
  } while (false)

#define ACL_CHECK_WITH_MESSAGE_AND_RETURN(exp, ret, ...) \
  do {                                                   \
    if (!(exp)) {                                        \
      ACL_LOG_ERROR(__VA_ARGS__);                        \
      return (ret);                                      \
    }                                                    \
  } while (false)

#define ACL_DELETE(memory) \
  do {                     \
    delete (memory);       \
    (memory) = nullptr;    \
  } while (false)

#define ACL_DELETE_ARRAY(memory)              \
  do {                                        \
    if ((memory) != nullptr) {                \
      delete[] static_cast<char_t *>(memory); \
      (memory) = nullptr;                     \
    }                                         \
  } while (false)

#define ACL_CHECK_WITH_INNER_MESSAGE_AND_RETURN(exp, ret, ...) \
  do {                                                         \
    if (!(exp)) {                                              \
      ACL_LOG_INNER_ERROR(__VA_ARGS__);                        \
      return (ret);                                            \
    }                                                          \
  } while (false)

#define ACL_DELETE_AND_SET_NULL(var) \
  do {                               \
    if ((var) != nullptr) {          \
      delete (var);                  \
      (var) = nullptr;               \
    }                                \
  } while (false)

#define ACL_DELETE_ARRAY_AND_SET_NULL(var) \
  do {                                     \
    if ((var) != nullptr) {                \
      delete[] (var);                      \
      (var) = nullptr;                     \
    }                                      \
  } while (false)

// If make_shared is abnormal, print the log and execute the statement
#define ACL_MAKE_SHARED(expr0, expr1)                        \
  try {                                                      \
    (expr0);                                                 \
  } catch (const std::bad_alloc &) {                         \
    ACL_LOG_INNER_ERROR("[Make][Shared]Make shared failed"); \
    expr1;                                                   \
  }

#define ACL_REQUIRES_EQ(x, y)                                                                  \
  do {                                                                                         \
    const auto &xv = (x);                                                                      \
    const auto &yv = (y);                                                                      \
    if (xv != yv) {                                                                            \
      std::stringstream ss;                                                                    \
      ss << "Assert (" << #x << " == " << #y << ") failed, expect " << yv << " actual " << xv; \
      ACL_LOG_INNER_ERROR("%s", ss.str().c_str());                                             \
      return ACL_ERROR_INVALID_PARAM;                                                          \
    }                                                                                          \
  } while (false)

#define ACL_CHECK_INT32_EQUAL(leftValue, rightValue)                         \
  do {                                                                       \
    if ((leftValue) != (rightValue)) {                                       \
      ACL_LOG_INFO("[%d] is not equal to [%d].", (leftValue), (rightValue)); \
      return false;                                                          \
    }                                                                        \
  } while (false)

#define ACL_REQUIRES_LE(x, y)                                                                                 \
  do {                                                                                                        \
    const auto &xv = (x);                                                                                     \
    const auto &yv = (y);                                                                                     \
    if (!(xv <= yv)) {                                                                                        \
      std::stringstream ss;                                                                                   \
      ss << "Assert (" << #x << " <= " << #y << ") failed, left value is " << xv << " right value is " << yv; \
      ACL_LOG_INNER_ERROR("%s", ss.str().c_str());                                                            \
      return ACL_ERROR_INVALID_PARAM;                                                                         \
    }                                                                                                         \
  } while (false)

#endif  // ACL_COMMON_LOG_H_