#ifndef LOG4_H
#define LOG4_H

#if defined(__cplusplus) && __cplusplus >= 201103L
  #define LOG_TLS_SPEC thread_local
#else
  /* C 或旧编译器，走 GCC 扩展 */
  #define LOG_TLS_SPEC __thread
#endif

/* ★统一的对外声明（别在其他头/源里再声明不同版本！） */
extern LOG_TLS_SPEC int g_log_code_tls;

#ifdef __cplusplus

#include <string>
#include <map>

//防止#include <log4cplus/logger.h>里的冲突
#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif
//防止#include <log4cplus/logger.h>里的冲突

#include "logger.h"
#include <set>
#include "loggingmacros.h"

#include "appender.h"

/////////////////////////////////////////////入参验证
#if defined(__GNUC__) || defined(__clang__)
#  define PRINTF_LIKE(fmt_index, first_arg) __attribute__((format(printf, fmt_index, first_arg)))
#else
#  define PRINTF_LIKE(fmt_index, first_arg)
#endif
/////////////////////////////////////////

struct LogLevelCache {      //日志等级缓存
    // terminal_id -> min_level
    std::unordered_map<std::string, int> term_min;
    // monitor_id  -> min_level
    std::unordered_map<std::string, int> mp_min;
};

////////////////////////////////////
struct TypedLogger {
    log4cplus::Logger logger;
    int logtype;
    TypedLogger();
    TypedLogger(const log4cplus::Logger& l, int t);
};

struct DebugSwitch {
    bool debug_open;
    std::set<std::string> targets;
    int min_level;
    std::map<int, bool> type_enable;

    DebugSwitch();
    void open();
    void close();
    void set_target(const std::string& name);
    void set_level(int level);
    void enable_type(int type);
    void disable_type(int type);
    bool match(const std::string& logger_name, int level, int logtype);
};

extern std::map<std::string, TypedLogger> logger_map;
extern DebugSwitch g_debug_switch;

extern void send_reply_to_queue(const std::string& guid, const int code, const std::string& result);

extern std::shared_ptr<LogLevelCache> g_level_cache_sp;
const char* loglevel_to_str(int lv);

// 不带 Appender 的版本
log4cplus::Logger init_logger(const std::string& full_name,
                              const std::string& file_dir,
                              const std::string& base_file);

// 带 Appender 的版本
log4cplus::Logger init_logger(const std::string& full_name,
                              const std::string& file_dir,
                              const std::string& base_file,
                              log4cplus::SharedAppenderPtr fileAppender);

void process_log_command(const std::string& id, const std::string& level, const std::string& grade, int logtype);


void update_log_entries_countdown();

void refresh_log_level_cache_locked();

extern "C" {
#endif
void remove_loggers_by_terminal_id(const std::string& terminal_id_cstr);
void init_logger_process();
void init_loggers();
void init_loggers_bydevid(const std::string& dev_id);

void log_debug(const char* key, const char* msg);
void log_info(const char* key, const char* msg);
void log_warn(const char* key, const char* msg);
void log_error(const char* key, const char* msg);
//void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...);
//带验证
void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...) PRINTF_LIKE(3,4);

// ====================== ★新增：线程局部变量透传 code ======================
// 说明：使用编译器的 TLS（__thread）保存当前日志的 code 值。
//      在每次打日志前写入，打完后恢复，Appender 读取该值写入 JSON。


// ====================== ★新增结束 ======================

typedef enum LogCode {
    LOG_CODE_WIRETYPE          = 96,    /* 接线类型 */
    LOG_CODE_CONFIG            = 97,    /* 配置相关 */
    LOG_CODE_JSON              = 98,    /* JSON结构 */
    LOG_CODE_OTHER             = 99,   /* 其他类型 */
    LOG_CODE_LEDGER            = 100,  /* 台账类型 */

    LOG_CODE_RPTINIT           = 101,  /* 报告初始化 */
    LOG_CODE_ICD_AND_DOWNLOAD  = 200,  /* ICD 类型 */

    LOG_CODE_TRANSIENT         = 300,  /* 暂态发生 */
    LOG_CODE_TRANSIENT_COMM    = 301,  /* 暂态接口 */
    LOG_CODE_FILE              = 302,  /* 文件上传 */
    LOG_CODE_MQ                = 400,  /* MQ发送 */
    LOG_CODE_RT_DATA           = 401,  /* 实时数据 */
    LOG_CODE_LEDGER_UPDATE     = 402,  /* 台账更新 */
    LOG_CODE_PROCESS_CONTROL   = 403,  /* 进程控制 */
    LOG_CODE_RECALL            = 404,  /* 补招相关 */
    LOG_CODE_LOG_REQUEST       = 405,  /* 日志请求 */
    LOG_CODE_CLOUD             = 406,  /* 云前置控制 */

    LOG_CODE_REPORT            = 500,  /* 报告处理 */

    LOG_CODE_COMM              = 600,  /* 通讯状态 */
    LOG_CODE_SPACE_ALARM       = 700,  /* 空间告警 */
    LOG_CODE_DEV_ALARM         = 800   /* 设备告警 */
} LogCode;

// ====================== 日志宏区域 ======================

// ★新增：带 code 的实现（C/C++ 通用，使用 TLS 保存/恢复）
#define DIY_LOG_CODE(LEVEL_FUNC, KEY, LEVEL_INT, CODE_INT, ...)                           \
    do {                                                                                  \
        /* 备份并设置本次日志 code */                                                     \
        int __old_code__ = g_log_code_tls;                                                \
        g_log_code_tls = static_cast<int>(CODE_INT);                                      \
                                                                                          \
        /* 组装消息 */                                                                    \
        char __msg_buf__[256];                                                            \
        format_log_msg(__msg_buf__, sizeof(__msg_buf__), __VA_ARGS__);                    \
                                                                                          \
        /* 将 KEY 规范化为字符串（兼容 const char* / std::string 等） */                 \
        std::ostringstream __oss_key__;                                                   \
        __oss_key__ << (KEY);                                                             \
        std::string __key_raw__ = __oss_key__.str();                                      \
                                                                                          \
        /* 根据 LEVEL_INT 构造最终 key */                                                 \
        char __key_buf__[256];                                                            \
        switch (static_cast<int>(LEVEL_INT)) {                                            \
            case 0:                                                                       \
                std::snprintf(__key_buf__, sizeof(__key_buf__), "process");               \
                break;                                                                    \
            case 1:                                                                       \
                std::snprintf(__key_buf__, sizeof(__key_buf__),                           \
                              "terminal.%s", __key_raw__.c_str());                        \
                break;                                                                    \
            case 2:                                                                       \
                std::snprintf(__key_buf__, sizeof(__key_buf__),                           \
                              "monitor.%s", __key_raw__.c_str());                         \
                break;                                                                    \
            default:                                                                      \
                std::snprintf(__key_buf__, sizeof(__key_buf__), "%s",                     \
                              __key_raw__.c_str());                                       \
                break;                                                                    \
        }                                                                                 \
                                                                                          \
        /* 输出日志 */                                                                    \
        LEVEL_FUNC(__key_buf__, __msg_buf__);                                             \
                                                                                          \
        /* 恢复旧值 */                                                                    \
        g_log_code_tls = __old_code__;                                                    \
    } while (0)

// ★修改：默认宏改为 code=0（兼容原有用法）
#define DIY_ERRORLOG(KEY, ...) DIY_LOG_CODE(log_error, KEY, 0, LOG_CODE_OTHER,__VA_ARGS__)   // ★修改：默认 code=0
#define DIY_WARNLOG(KEY,  ...) DIY_LOG_CODE(log_warn,  KEY, 0, LOG_CODE_OTHER,__VA_ARGS__)   // ★修改：默认 code=0
#define DIY_INFOLOG(KEY,  ...) DIY_LOG_CODE(log_info,  KEY, 0, LOG_CODE_OTHER,__VA_ARGS__)   // ★修改：默认 code=0
#define DIY_DEBUGLOG(KEY, ...) DIY_LOG_CODE(log_debug, KEY, 0, LOG_CODE_OTHER,__VA_ARGS__)   // ★修改：默认 code=0

// ★新增：显式传入 code 的便捷宏
// 用法示例：DIY_WARNLOG_CODE(full_key_m_c, warn_recallstart, "监测点:%s ...", ...);
#define DIY_ERRORLOG_CODE(KEY, LEVEL_INT,CODE_INT, ...) DIY_LOG_CODE(log_error, KEY, LEVEL_INT, CODE_INT, __VA_ARGS__)  // ★新增
#define DIY_WARNLOG_CODE(KEY,  LEVEL_INT,CODE_INT, ...) DIY_LOG_CODE(log_warn,  KEY, LEVEL_INT, CODE_INT, __VA_ARGS__)  // ★新增
#define DIY_INFOLOG_CODE(KEY,  LEVEL_INT,CODE_INT, ...) DIY_LOG_CODE(log_info,  KEY, LEVEL_INT, CODE_INT, __VA_ARGS__)  // ★新增
#define DIY_DEBUGLOG_CODE(KEY, LEVEL_INT,CODE_INT, ...) DIY_LOG_CODE(log_debug, KEY, LEVEL_INT, CODE_INT, __VA_ARGS__)  // ★新增


// ====================== 日志宏区域 ======================

#ifdef __cplusplus
}
#endif



#endif // LOG4_H
