#include "type.h"
#include "agent_log.h"
#include "platform.h"
#include <string.h>   // 提供 memset/strlen
#include <stdarg.h>   // 强制包含，确保 va_list 生效（避免头文件依赖失效）
#include <errno.h>    // 强制包含，确保 errno 生效
#include <stdarg.h>   // 定义 va_list/va_start/va_end

// 日志系统全局配置
static AgentLogConfig g_log_config = {
    .level = AGENT_LOG_WARN,       // 默认输出INFO及以上级别
    .dest = AGENT_LOG_DEST_CONSOLE,// 默认只输出到控制台
    .max_flash_size = 0,
    .max_log_length = 256
};

// 日志级别字符串映射
static const char* g_log_level_str[] = {
    [AGENT_LOG_DEBUG] = "DEBUG",
    [AGENT_LOG_INFO]  = "INFO",
    [AGENT_LOG_WARN]  = "WARN",
    [AGENT_LOG_ERROR] = "ERROR",
    [AGENT_LOG_FATAL] = "FATAL"
};

/**
 * @brief 初始化日志系统
 * @param config 日志配置参数
 */
void agent_log_init(const AgentLogConfig* config) {
    if (config == NULL) return;
    
    // 拷贝配置参数（只使用有效字段）
    g_log_config.level = config->level;
    g_log_config.dest = config->dest;
    
    // 限制最大日志长度在合理范围
    if (config->max_log_length > 0 && config->max_log_length <= 1024) {
        g_log_config.max_log_length = config->max_log_length;
    } else {
        g_log_config.max_log_length = 256;
    }
    
    // 初始化信息打印
    agent_log_info("日志系统初始化完成，级别: %s，目标: 0x%x",
                  g_log_level_str[g_log_config.level],
                  g_log_config.dest);
}

/**
 * @brief 控制台日志输出实现
 * @param level 日志级别
 * @param message 日志内容
 */
static void log_to_console(AgentLogLevel level, const char* message) {
    if (message == NULL) return;
    
    // 获取当前时间戳
    uint32 timestamp = platform_get_tick_ms();
    
    // 格式化输出（时间戳 级别 内容）
    printf("[%u] [%s] %s\n", timestamp, g_log_level_str[level], message);
}

/**
 * @brief 核心日志输出函数
 * @param level 日志级别
 * @param fmt 格式化字符串
 * @param ... 可变参数列表
 */
void agent_log(AgentLogLevel level, const char* fmt, ...) {
    // 检查日志级别是否满足输出条件
    if (level < g_log_config.level) {
        return;
    }
    
    // 检查输出目标是否包含控制台
    if (!(g_log_config.dest & AGENT_LOG_DEST_CONSOLE)) {
        return;
    }
    
    // 检查参数有效性
    if (fmt == NULL) {
        return;
    }
    
    // 格式化日志内容
    char log_buf[1024] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(log_buf, sizeof(log_buf) - 1, fmt, args);
    va_end(args);
    
    // 输出到控制台
    log_to_console(level, log_buf);
}

/**
 * @brief 获取日志条目数量（预留接口）
 * @return 当前日志条目数量
 */
uint16 agent_log_get_count(void) {
    // 目前仅支持控制台输出，无存储，返回0
    return 0;
}

void agent_log_hexdump(const char* prefix, const uint8* data, uint16 len) {
    if (prefix && data && len > 0) {
        agent_log_debug("%s", prefix);
    }

    char hex_buf[16 * 3 + 1]; // 每个字节用两个十六进制字符加一个空格
    hex_buf[sizeof(hex_buf) - 1] = '\0';

    for (uint16 i = 0; i < len; i++) {
        // --- 安全修改 ---
        char* current_pos = &hex_buf[i % 16 * 3];
        size_t remaining_space = sizeof(hex_buf) - (current_pos - hex_buf);

        int ret = sprintf_s(current_pos, remaining_space, "%02X ", data[i]);
        if (ret < 0) {
            agent_log_error("agent_log_hexdump: sprintf_s failed! i=%d, remaining_space=%zu, errno=%d",
                           i, remaining_space, errno);
            break;
        }
        // --- 安全修改结束 ---

        if ((i + 1) % 16 == 0 || i == len - 1) {
            agent_log_debug("%s", hex_buf);
            memset(hex_buf, ' ', sizeof(hex_buf) - 1);
            hex_buf[sizeof(hex_buf) - 1] = '\0';
        }
    }
}


/**
 * @brief 获取指定索引的日志条目（预留接口）
 * @param index 日志索引
 * @param entry 输出日志条目
 * @return 获取成功返回TRUE，否则返回FALSE
 */
bool8 agent_log_get_entry(uint16 index, AgentLogEntry* entry) {
    // 目前仅支持控制台输出，无存储，返回FALSE
    (void)index;
    (void)entry;
    return BOOL8_FALSE;
}

/**
 * @brief 清空FLASH中的日志（预留接口）
 */
void agent_log_clear_flash(void) {
    // 目前无FLASH存储，仅打印调试信息
    agent_log_debug("尝试清空FLASH日志（未实现）");
}
    
void agent_log_printf(const char* format, ...) {
    char log_buf[256] = {0};
    va_list args;
    va_start(args, format);
    vsnprintf(log_buf, sizeof(log_buf), format, args);
    va_end(args);
    
    // 调用现有日志接口（示例：假设 agent_log_info 可接收字符串）
    agent_log_info("%s", log_buf);
}
/**
 * 设置日志输出级别
 * 动态调整日志过滤门槛（仅输出级别 >= 设置级别的日志）
 */
void agent_log_set_level(AgentLogLevel level) {
    // 校验级别合法性（超出范围时不修改）
    if (level < AGENT_LOG_DEBUG || level > AGENT_LOG_FATAL) {
        agent_log_error("无效的日志级别: %d（范围：0-%d）", 
                       level, AGENT_LOG_FATAL);
        return;
    }

    // 记录级别变更日志（使用原级别输出，确保变更可见）
    AgentLogLevel old_level = g_log_config.level;
    g_log_config.level = level;

    agent_log_info("日志级别已变更: %s → %s",
                  g_log_level_str[old_level],
                  g_log_level_str[level]);
}


