/*********************************************************************
 * @file    user_mib.c
 * @brief   用户自定义MIB节点实现（温度、LED、风扇）
 *********************************************************************/
#include "user_mib.h"
#include "snmp_ber.h"      // 使用SNMP_BER_*类型和错误码
#include "mib_registry.h"  // MIB注册表接口
#include "agent_log.h"     // 引入统一日志头文件
#include <stdio.h>
#include <string.h>
#include "agent_trap.h"

// --------------------------
// 1. OID定义（修复企业号12345的表示方式）
// --------------------------
// 企业私有基础前缀：1.3.6.1.4.1（使用uint32数组存储节点值）
static const uint32 g_enterprise_base_prefix[] = {1, 3, 6, 1, 4, 1};
static const uint8 g_enterprise_base_prefix_len = 
    sizeof(g_enterprise_base_prefix) / sizeof(g_enterprise_base_prefix[0]);
static const uint32 g_enterprise_number = 12345;  // 企业号（支持大于127的值）

// 节点后缀（完整OID = 基础前缀 + 企业号 + 后缀）
static const uint32 g_temp_suffix[] = {1, 1};    // 温度：1.3.6.1.4.1.12345.1.1
static const uint32 g_led_suffix[] = {1, 2};     // LED：1.3.6.1.4.1.12345.1.2
static const uint32 g_fan_suffix[] = {1, 3};     // 风扇：1.3.6.1.4.1.12345.1.3

// 存储完整OID（使用snmp_protocol.h定义的SnmpOid）
static SnmpOid s_temp_oid = {.data = {0}, .len = 0};
static SnmpOid s_led_oid = {.data = {0}, .len = 0};
static SnmpOid s_fan_oid = {.data = {0}, .len = 0};

// --------------------------
// 2. 硬件模拟
// --------------------------
typedef struct {
    uint16 temp_reg;  // 温度（毫开尔文：27315 = 0℃）
    uint8  led_reg;   // LED状态（0=关，1=开）
    uint16 fan_reg;   // 风扇PWM（0~1000）
} SimRegs;

static SimRegs s_regs = {
    .temp_reg = 29815U,  // 25℃（298.15K）
    .led_reg = 0U,       // 初始关闭
    .fan_reg = 500U      // 50%占空比
};

// 参数范围
#define TEMP_MIN_C    -40
#define TEMP_MAX_C     85
#define FAN_PWM_MIN    0
#define FAN_PWM_MAX  1000

// --------------------------
// 3. 工具函数
// --------------------------
static SimRegs* get_regs(void) {
    return &s_regs;
}

/**
 * 构建OID（前缀+企业号+后缀）- 适配uint32节点数组
 */
static bool8 build_oid(SnmpOid* oid, const uint32* prefix, uint8 p_len,
                      uint32 enterprise,
                      const uint32* suffix, uint8 s_len) {
    if (!oid || !prefix || !suffix) {
        agent_log_error("构建OID失败：无效参数（空指针）");
        return BOOL8_FALSE;
    }
    
    // 检查总长度是否超过最大值
    if (p_len + 1 + s_len > MAX_OID_LEN) {
        agent_log_error("构建OID失败：长度超出最大值（%d > %d）",
                       p_len + 1 + s_len, MAX_OID_LEN);
        return BOOL8_FALSE;
    }

    // 拼接完整OID（直接存储uint32节点值）
    uint16 pos = 0;
    
    // 复制前缀
    for (uint8 i = 0; i < p_len; i++) {
        oid->data[pos++] = prefix[i];
    }
    
    // 添加企业号（支持大于127的值）
    oid->data[pos++] = enterprise;
    
    // 复制后缀
    for (uint8 i = 0; i < s_len; i++) {
        oid->data[pos++] = suffix[i];
    }
    
    oid->len = pos;
    agent_log_debug("OID构建成功，节点数：%d", oid->len);
    return BOOL8_TRUE;
}

// --------------------------
// 4. 节点回调函数
// --------------------------

/**
 * 温度传感器（只读，INTEGER类型）
 */
static SnmpBerResult temp_read(void* user_data, SnmpVarBind* varbind) {
    (void)user_data;
    if (!varbind) {
        agent_log_error("温度读取失败：varbind参数为空");
        return SNMP_BER_ERR_INVALID_PARAM;
    }

    SimRegs* regs = get_regs();
    uint16 raw = regs->temp_reg;
    agent_log_debug("温度原始值读取：%u毫开", raw);

    // 校验范围（-40℃~85℃ → 23315~35815毫开）
    if (raw < 23315U || raw > 35815U) {
        agent_log_error("温度超出范围（%u毫开），有效范围23315~35815毫开", raw);
        return SNMP_BER_ERR_GEN_ERR;
    }

    // 转换为摄氏度
    varbind->type = SNMP_BER_TYPE_INTEGER;
    varbind->value.integer = (raw - 27315) / 100;

    agent_log_info("温度读取成功：%d℃", varbind->value.integer);
    return SNMP_BER_SUCCESS;
}

/**
 * LED控制（读写，INTEGER类型）
 */
static SnmpBerResult led_read(void* user_data, SnmpVarBind* varbind) {
    (void)user_data;
    if (!varbind) {
        agent_log_error("LED读取失败：varbind参数为空");
        return SNMP_BER_ERR_INVALID_PARAM;
    }

    varbind->type = SNMP_BER_TYPE_INTEGER;
    varbind->value.integer = get_regs()->led_reg;

    agent_log_info("LED状态读取成功：%hhu（0=关，1=开）", get_regs()->led_reg);
    return SNMP_BER_SUCCESS;
}

static SnmpBerResult led_write(void* user_data, const SnmpVarBind* varbind) {
    (void)user_data;
    if (!varbind) {
        agent_log_error("LED写入失败：varbind参数为空");
        return SNMP_BER_ERR_INVALID_PARAM;
    }

    // 类型校验
    if (varbind->type != SNMP_BER_TYPE_INTEGER) {
        agent_log_error("LED写入失败：类型错误（0x%02X），预期INTEGER(0x%02X)",
                       varbind->type, SNMP_BER_TYPE_INTEGER);
        return SNMP_BER_ERR_WRONG_TYPE;
    }

    // 值校验（0或1）
    int32 val = varbind->value.integer;
    if (val < 0 || val > 1) {
        agent_log_error("LED写入失败：值无效（%d），有效范围0~1", val);
        return SNMP_BER_ERR_WRONG_VALUE;
    }

    // 4. 临界区保护写入硬件寄存器（裸机场景必加）
    uint32 primask = platform_irq_save(); // 关闭全局中断，避免竞态
    get_regs()->led_reg = (uint8)val;
    platform_irq_restore(primask); // 恢复中断

    // 5. 回读校验（确保寄存器写入成功）
    if (get_regs()->led_reg != (uint8)val) {
        agent_log_error("LED写入失败：寄存器回读值不匹配（写入%d，实际%d）",
                       val, get_regs()->led_reg);
        return SNMP_BER_ERR_GEN_ERR;
    }

    // 6. 成功写入后，联动 Trap/Inform（调用无参数接口）
    agent_log_info("LED状态写入成功：%hhu（0=关，1=开）", get_regs()->led_reg);
    if (val == 0) {
        // 6.1 LED 关闭 → 发送链路断开 Trap（无参数，自动选择NMS）
        agent_log_info("触发链路断开 Trap（自动匹配NMS地址）");
        bool8 trap_ok = agent_send_v2c_link_down_trap_auto();
        if (!trap_ok) {
            agent_log_warn("链路断开 Trap 发送失败（不影响LED写入结果）");
        }
    } else if (val == 1) {
        // 6.2 LED 开启 → 发送链路恢复 Inform（无参数，自动选择NMS）
        agent_log_info("触发链路恢复 Inform（自动匹配NMS地址）");
        bool8 inform_ok = agent_send_v2c_link_up_inform_auto();
        if (!inform_ok) {
            agent_log_warn("链路恢复 Inform 发送失败（不影响LED写入结果）");
        }
    }

    return SNMP_BER_SUCCESS;
}

/**
 * 风扇转速（只读，GAUGE32类型）
 */
static SnmpBerResult fan_read(void* user_data, SnmpVarBind* varbind) {
    (void)user_data;
    if (!varbind) {
        agent_log_error("风扇读取失败：varbind参数为空");
        return SNMP_BER_ERR_INVALID_PARAM;
    }

    // PWM转转速（PWM×10 → 0~10000 RPM）
    uint32 speed = (uint32)get_regs()->fan_reg * 10U;
    if (speed > 10000U) {
        speed = 10000U;
        agent_log_warn("风扇转速超出最大值，已截断为10000RPM");
    }

    varbind->type = SNMP_BER_TYPE_GAUGE32;
    varbind->value.gauge32 = speed;

    agent_log_info("风扇转速读取成功：%u RPM", speed);
    return SNMP_BER_SUCCESS;
}

// --------------------------
// 5. 节点注册
// --------------------------
void user_mib_init(void) {
    agent_log_info("开始初始化用户自定义MIB节点");

    // 构建子节点OID，包含正确编码的企业号12345
    bool8 oid_ok = BOOL8_TRUE;
    oid_ok &= build_oid(&s_temp_oid, 
                       g_enterprise_base_prefix, g_enterprise_base_prefix_len,
                       g_enterprise_number,
                       g_temp_suffix, sizeof(g_temp_suffix)/sizeof(g_temp_suffix[0]));
    oid_ok &= build_oid(&s_led_oid, 
                       g_enterprise_base_prefix, g_enterprise_base_prefix_len,
                       g_enterprise_number,
                       g_led_suffix, sizeof(g_led_suffix)/sizeof(g_led_suffix[0]));
    oid_ok &= build_oid(&s_fan_oid, 
                       g_enterprise_base_prefix, g_enterprise_base_prefix_len,
                       g_enterprise_number,
                       g_fan_suffix, sizeof(g_fan_suffix)/sizeof(g_fan_suffix[0]));

    if (!oid_ok) {
        agent_log_fatal("用户自定义MIB初始化失败：OID构建失败");
        return;
    }

    // 注册温度节点
    MibNodeConfig temp_cfg = {
        .oid = s_temp_oid,
        .type = SNMP_BER_TYPE_INTEGER,
        .perm = MIB_PERM_READ_ONLY,
        .op = {.read = temp_read, .write = NULL},
        .user_data = NULL,
        .name = "tempSensor",
        .poll_interval = 1000  // 1秒轮询
    };
    if (mib_registry_add(&temp_cfg)) {
        agent_log_info("温度节点注册成功：%s", temp_cfg.name);
    } else {
        agent_log_error("温度节点注册失败：%s", temp_cfg.name);
    }

    // 注册LED节点
    MibNodeConfig led_cfg = {
        .oid = s_led_oid,
        .type = SNMP_BER_TYPE_INTEGER,
        .perm = MIB_PERM_READ_WRITE,
        .op = {.read = led_read, .write = led_write},
        .user_data = NULL,
        .name = "ledControl",
        .poll_interval = MIB_NO_POLL
    };
    if (mib_registry_add(&led_cfg)) {
        agent_log_info("LED节点注册成功：%s", led_cfg.name);
    } else {
        agent_log_error("LED节点注册失败：%s", led_cfg.name);
    }

    // 注册风扇节点
    MibNodeConfig fan_cfg = {
        .oid = s_fan_oid,
        .type = SNMP_BER_TYPE_GAUGE32,
        .perm = MIB_PERM_READ_ONLY,
        .op = {.read = fan_read, .write = NULL},
        .user_data = NULL,
        .name = "fanSpeed",
        .poll_interval = 500  // 500ms轮询
    };
    if (mib_registry_add(&fan_cfg)) {
        agent_log_info("风扇节点注册成功：%s", fan_cfg.name);
    } else {
        agent_log_error("风扇节点注册失败：%s", fan_cfg.name);
    }

    agent_log_info("用户自定义MIB初始化完成（3个节点）");
}

// --------------------------
// 6. 外部接口
// --------------------------
const SnmpOid* user_mib_get_oid(UserMibNode node) {
    switch (node) {
        case USER_MIB_TEMP_SENSOR:
            agent_log_debug("获取温度节点OID");
            return &s_temp_oid;
        case USER_MIB_LED_CONTROL:
            agent_log_debug("获取LED节点OID");
            return &s_led_oid;
        case USER_MIB_FAN_SPEED:
            agent_log_debug("获取风扇节点OID");
            return &s_fan_oid;
        default:
            agent_log_warn("获取无效节点OID：%d", node);
            return NULL;
    }
}

bool8 user_mib_simulate_hw(int32 temp, uint8 led_state, uint16 fan_pwm) {
    // 参数校验
    if (temp < TEMP_MIN_C || temp > TEMP_MAX_C) {
        agent_log_error("硬件模拟失败：温度超出范围（%d℃），有效范围%d~%d℃",
                       temp, TEMP_MIN_C, TEMP_MAX_C);
        return BOOL8_FALSE;
    }
    if (led_state > 1) {
        agent_log_error("硬件模拟失败：LED状态无效（%hhu），有效值0~1", led_state);
        return BOOL8_FALSE;
    }
    if (fan_pwm < FAN_PWM_MIN || fan_pwm > FAN_PWM_MAX) {
        agent_log_error("硬件模拟失败：风扇PWM超出范围（%u），有效范围%d~%d",
                       fan_pwm, FAN_PWM_MIN, FAN_PWM_MAX);
        return BOOL8_FALSE;
    }

    // 更新寄存器
    SimRegs* regs = get_regs();
    regs->temp_reg = 27315U + (uint16)(temp * 100);  // 转换为毫开
    regs->led_reg = led_state;
    regs->fan_reg = fan_pwm;

    agent_log_info("硬件模拟更新成功：温度=%d℃, LED=%hhu, 风扇PWM=%u",
                  temp, led_state, fan_pwm);
    return BOOL8_TRUE;
}
    
