/** @file dc_signal_param.cpp — Param 信号注册/控制/异步执行 */
#include "dc_internal.h"

/**
 * @brief 创建 Param 定值信号：若已存在则复制各 zone 旧值并替换指针；新注册则执行 metadata_lookup 并标记 changed
 */
extern "C" int dc_signal_param(const char *saddr, const char *desc, uint8_t data_type, uint8_t ctrl_type, void **p_data, int num_zones, dc_signal_change_cb_t cb, const char *module_id)
{
    if (!g_initialized || !saddr || !p_data || !module_id)
    {
        return DC_ERR_PARAM;
    }

    if (num_zones <= 0 || num_zones > DC_MAX_DATA_ZONES)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *existing = dc_core_find(saddr, g_dc_param);

    if (existing && existing->data_type != data_type)
    {
        LOG_E("param %s data_type mismatch %d!=%d\n", saddr, existing->data_type, data_type);

        return DC_ERR_TYPE;
    }

    if (existing)
    {
        for (int i = 0; i < num_zones && i < existing->vec_p_data_count; i++)
        {
            dc_util_val_copy(p_data[i], existing->vec_p_data[i], existing->data_type);
        }
    }

    dc_signal_t sig = {};
    sig.hash = XXH3_128bits(saddr, strlen(saddr));
    strncpy(sig.saddr, saddr, DC_SADDR_MAX_LEN - 1);

    if (desc)
    {
        strncpy(sig.desc, desc, DC_DESC_MAX_LEN - 1);
    }

    sig.data_type = data_type;
    sig.ctrl_type = ctrl_type;
    sig.vec_p_data = (void **)malloc(sizeof(void *) * num_zones);

    for (int i = 0; i < num_zones; i++)
    {
        sig.vec_p_data[i] = p_data[i];
    }

    sig.vec_p_data_count = num_zones;

    if (!existing)
    {
        dc_param_meta_t meta;

        if (dc_param_metadata_lookup(saddr, meta))
        {
            sig.param = meta;
        }
    }
    else
    {
        sig.param = existing->param;

        for (int i = 0; i < existing->cb_count && sig.cb_count < DC_MAX_CALLBACKS; i++)
        {
            sig.cb_list[sig.cb_count] = existing->cb_list[i];
            sig.cb_count++;
        }
    }

    if (cb && sig.cb_count < DC_MAX_CALLBACKS)
    {
        strncpy(sig.cb_list[sig.cb_count].module_id, module_id, DC_MODULE_MAX_LEN - 1);
        sig.cb_list[sig.cb_count].ctrl_cb = cb;
        sig.cb_count++;
    }

    g_param_cfg_changed = true;

    return dc_core_add(sig, g_dc_param);
}

/**
 * @brief 链接已有 Param 信号：将各 zone 的 p_data 指向信号的 vec_p_data，可选添加 cb
 */
extern "C" int dc_signal_param_link_with_callback(const char *saddr, void **p_data, int num_zones, dc_signal_change_cb_t cb, const char *module_id)
{
    if (!g_initialized || !saddr || !p_data || !module_id)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_param);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (num_zones > ps->vec_p_data_count)
    {
        return DC_ERR_PARAM;
    }

    for (int i = 0; i < num_zones; i++)
    {
        p_data[i] = ps->vec_p_data[i];
    }

    if (cb && ps->cb_count < DC_MAX_CALLBACKS)
    {
        strncpy(ps->cb_list[ps->cb_count].module_id, module_id, DC_MODULE_MAX_LEN - 1);
        ps->cb_list[ps->cb_count].ctrl_cb = cb;
        ps->cb_count++;
    }

    return DC_OK;
}

/**
 * @brief 同步 Param 设值：ctrl 校验 + val 校验 → step 处理 → 遍历回调（跳过发起方 module_id）→ 标记 changed
 */
extern "C" int dc_signal_param_set_val(const char *saddr, dc_ctrl_step_t step, dc_ctrl_t *ctrl, uint8_t setting_zone, const void *p_data, const char *module_id)
{
    if (!g_initialized || !saddr || !ctrl || !p_data || !module_id)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_param);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    int ret = dc_check_ctrl_valid(ps, step, ctrl, p_data);

    if (ret != DC_OK)
    {
        return ret;
    }

    ret = dc_check_val_valid(ps, setting_zone, p_data);

    if (ret != DC_OK)
    {
        return ret;
    }

    if (step == DC_STEP_SELECT)
    {
        dc_util_val_copy(ctrl->p_data, p_data, ps->data_type);
    }
    else if (step == DC_STEP_DIRECT)
    {
        dc_util_val_copy(ps->vec_p_data[setting_zone], p_data, ps->data_type);
    }
    /* DC_STEP_CANCEL: no data operation */

    ctrl->step = step;

    for (int i = 0; i < ps->cb_count; i++)
    {
        if (!ps->cb_list[i].ctrl_cb)
        {
            continue;
        }

        if (0 == strcmp(ps->cb_list[i].module_id, module_id))
        {
            continue;
        }

        ps->cb_list[i].ctrl_cb(ps->saddr, step, ps->data_type, setting_zone, ps->vec_p_data[setting_zone]);
    }

    g_param_cfg_changed = true;

    return DC_OK;
}

/**
 * @brief 跳过 ctrl 校验直接写入 Param 值：校验 zone → 写数据 → 遍历回调（跳过发起方 module_id）→ 标记 changed
 */
extern "C" int dc_signal_param_set_val_without_check(const char *saddr, uint8_t data_type, uint8_t setting_zone, const void *p_data, const char *module_id)
{
    if (!g_initialized || !saddr || !p_data || !module_id)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_param);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    if (setting_zone >= (uint8_t)ps->vec_p_data_count)
    {
        return DC_ERR_PARAM;
    }

    dc_util_val_copy(ps->vec_p_data[setting_zone], p_data, data_type);

    for (int i = 0; i < ps->cb_count; i++)
    {
        if (!ps->cb_list[i].ctrl_cb)
        {
            continue;
        }

        if (0 == strcmp(ps->cb_list[i].module_id, module_id))
        {
            continue;
        }

        ps->cb_list[i].ctrl_cb(ps->saddr, DC_STEP_DIRECT, ps->data_type, setting_zone, ps->vec_p_data[setting_zone]);
    }

    g_param_cfg_changed = true;

    return DC_OK;
}

/**
 * @brief 发起 Param 异步执行请求
 */
extern "C" int dc_param_exec_async(const char *saddr, dc_ctrl_step_t step, const dc_ctrl_t *ctrl, uint8_t setting_zone, const void *p_data, const char *module_id, dc_async_result_cb_t result_cb, void *user_arg, uint32_t timeout_ms, uint32_t *request_id)
{
    if (!g_initialized || !saddr || !ctrl || !p_data || !module_id)
    {
        return DC_ERR_PARAM;
    }

    uint32_t req_id = dc_async_enqueue(g_dc_param, saddr, step, ctrl, p_data, setting_zone, 2, module_id, result_cb, user_arg, timeout_ms);

    if (request_id)
    {
        *request_id = req_id;
    }

    return (req_id == 0) ? DC_ERR_FULL : DC_OK;
}

/**
 * @brief 模块 B 返回 Param 异步执行结果
 */
extern "C" int dc_param_set_result(uint32_t request_id, int result_code, const char *err_msg)
{
    return dc_async_set_result(request_id, result_code, err_msg);
}

/**
 * @brief 取消未完成的 Param 异步请求
 */
extern "C" int dc_param_cancel_async(uint32_t request_id)
{
    return dc_async_cancel(request_id);
}

/**
 * @brief 注册 Param 异步执行回调（模块 B 调用）
 */
extern "C" int dc_param_register_exec_cb(const char *saddr, dc_async_exec_cb_t exec_cb, void *module_ctx)
{
    if (!g_initialized || !saddr)
    {
        return DC_ERR_PARAM;
    }

    dc_signal_t *ps = dc_core_find(saddr, g_dc_param);

    if (!ps)
    {
        return DC_ERR_NOTFOUND;
    }

    ps->exec_cb = exec_cb;
    ps->module_ctx = module_ctx;

    return DC_OK;
}

