/** @file dc_async.cpp — 异步请求队列管理 */
#include "dc_internal.h"
#include <sys/time.h>

/**
 * @brief 获取单调时钟毫秒数
 * @return 自系统启动以来的毫秒数
 */
static uint64_t dc_get_monotonic_ms(void)
{
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

/**
 * @brief 将异步请求加入队列
 * @param smap 信号表
 * @param saddr 信号地址
 * @param step 控制步骤
 * @param ctrl 控制上下文
 * @param p_data 数据指针
 * @param setting_zone 定值区号
 * @param signal_type 信号类型（0=yk, 1=ao, 2=param）
 * @param caller_module 调用方模块名
 * @param result_cb 结果回调
 * @param user_arg 用户参数
 * @param timeout_ms 超时毫秒数（0=使用默认值）
 * @return request_id（>0），失败返回 0
 */
uint32_t dc_async_enqueue(dc_signal_map_t &smap, const char *saddr,
                           dc_ctrl_step_t step, const dc_ctrl_t *ctrl,
                           const void *p_data, uint8_t setting_zone,
                           uint8_t signal_type, const char *caller_module,
                           dc_async_result_cb_t result_cb, void *user_arg,
                           uint32_t timeout_ms)
{
    dc_async_exec_cb_t sig_exec_cb = NULL;
    void *sig_ctx = NULL;
    dc_signal_t *ps = dc_core_find(saddr, smap);

    if (ps)
    {
        sig_exec_cb = ps->exec_cb;
        sig_ctx = ps->module_ctx;
    }

    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    if (g_async_queue.count >= g_async_queue.max_pending)
    {
        LOG_E("async queue full\n");

        return 0;
    }

    if (!timeout_ms)
    {
        uint32_t *pt = NULL;

        switch (signal_type)
        {
        case 0:
            pt = &g_async_queue.default_timeout_yk_ms;
            break;
        case 1:
            pt = &g_async_queue.default_timeout_ao_ms;
            break;
        case 2:
            pt = &g_async_queue.default_timeout_param_ms;
            break;
        }

        timeout_ms = (pt && *pt) ? *pt : g_async_queue.default_timeout_ms;
    }

    dc_async_request_t *req = new dc_async_request_t();

    memset(req, 0, sizeof(*req));

    if (++g_async_queue.next_id == 0)
    {
        ++g_async_queue.next_id;
    }

    req->request_id = g_async_queue.next_id;

    if (saddr)
    {
        strncpy(req->saddr, saddr, DC_SADDR_MAX_LEN - 1);
    }

    req->step = step;
    req->setting_zone = setting_zone;
    req->signal_type = signal_type;

    if (ctrl)
    {
        req->data_type = ctrl->data_type;
        req->ctrl_type = ctrl->type;
    }

    if (ctrl && ctrl->p_data && p_data)
    {
        req->p_select_data = dc_util_create_data(ctrl->data_type);

        if (req->p_select_data)
        {
            dc_util_val_copy(req->p_select_data, ctrl->p_data, ctrl->data_type);
        }

        req->p_direct_data = dc_util_create_data(ctrl->data_type);

        if (req->p_direct_data)
        {
            dc_util_val_copy(req->p_direct_data, p_data, ctrl->data_type);
        }
    }

    req->start_time_ms = dc_get_monotonic_ms();
    req->timeout_ms = timeout_ms;

    if (caller_module)
    {
        strncpy(req->caller_module, caller_module, DC_MODULE_MAX_LEN - 1);
    }

    req->result_cb = result_cb;
    req->user_arg = user_arg;
    req->exec_cb = sig_exec_cb;
    req->module_ctx = sig_ctx;

    req->next = g_async_queue.head;
    g_async_queue.head = req;
    g_async_queue.count++;
    g_async_queue.req_map[req->request_id] = req;

    return req->request_id;
}

/**
 * @brief 设置异步请求的执行结果
 * @param request_id 请求 ID
 * @param result_code 结果码（0=成功，负值=错误）
 * @param err_msg 错误信息
 * @return DC_OK 成功，DC_ERR_NOTFOUND/DC_ERR_TIMEOUT 失败
 */
int dc_async_set_result(uint32_t request_id, int result_code, const char *err_msg)
{
    dc_async_result_cb_t cb = NULL;
    void *arg = NULL;
    int existed = 0;

    {
        std::lock_guard<std::mutex> lk(g_async_queue.mtx);
        auto it = g_async_queue.req_map.find(request_id);

        if (it == g_async_queue.req_map.end())
        {
            return DC_ERR_NOTFOUND;
        }

        dc_async_request_t *req = it->second;

        if (req->result_code == DC_ERR_TIMEOUT)
        {
            LOG_I("req %u timeout, ignore\n", request_id);

            return DC_ERR_TIMEOUT;
        }

        req->result_code = result_code;

        if (err_msg)
        {
            strncpy(req->err_msg, err_msg, DC_ERR_MSG_MAX_LEN - 1);
        }

        cb = req->result_cb;
        arg = req->user_arg;
        existed = 1;
    }

    if (existed && cb)
    {
        cb(request_id, result_code, err_msg, arg);
    }

    return DC_OK;
}

/**
 * @brief 取消未完成的异步请求
 * @param request_id 请求 ID
 * @return DC_OK 成功，DC_ERR_NOTFOUND/DC_ERR_STEP 失败
 */
int dc_async_cancel(uint32_t request_id)
{
    dc_async_result_cb_t cb = NULL;
    void *arg = NULL;

    {
        std::lock_guard<std::mutex> lk(g_async_queue.mtx);
        auto it = g_async_queue.req_map.find(request_id);

        if (it == g_async_queue.req_map.end())
        {
            return DC_ERR_NOTFOUND;
        }

        dc_async_request_t *req = it->second;

        if (req->result_code != 0)
        {
            return DC_ERR_STEP;
        }

        req->result_code = DC_ERR_CANCEL;
        snprintf(req->err_msg, sizeof(req->err_msg), "cancelled");
        cb = req->result_cb;
        arg = req->user_arg;
    }

    if (cb)
    {
        cb(request_id, DC_ERR_CANCEL, "cancelled", arg);
    }

    return DC_OK;
}

/**
 * @brief 超时检测：遍历队列，标记超时请求并触发回调
 */
void dc_async_timeout_check(void)
{
	uint64_t now = dc_get_monotonic_ms();
	dc_async_request_t *req;

	/* 第一阶段: 持锁标记超时, 收集超时回调列表 */
	std::vector<dc_async_result_cb_t>  timeout_cbs;
	std::vector<uint32_t>              timeout_ids;
	std::vector<int>                   timeout_codes;
	std::vector<char *>                timeout_msgs;
	std::vector<void *>                timeout_args;

	{
		std::lock_guard<std::mutex> lk(g_async_queue.mtx);

		for (req = g_async_queue.head; NULL != req; req = req->next)
		{
			if (req->result_code == 0 && (now - req->start_time_ms) >= req->timeout_ms)
			{
				req->result_code = DC_ERR_TIMEOUT;
				snprintf(req->err_msg, sizeof(req->err_msg), "timeout %ums", req->timeout_ms);

				if (NULL != req->result_cb)
				{
					timeout_ids.push_back(req->request_id);
					timeout_codes.push_back(DC_ERR_TIMEOUT);
					timeout_msgs.push_back(req->err_msg);
					timeout_args.push_back(req->user_arg);
					timeout_cbs.push_back(req->result_cb);
				}
			}
		}
	}

	/* 第二阶段: 解锁后调用回调, 避免死锁 (回调可能再次入队) */
	for (uint32_t i = 0; i < timeout_cbs.size(); i++)
	{
		timeout_cbs[i](timeout_ids[i], timeout_codes[i], timeout_msgs[i], timeout_args[i]);
	}
}

/**
 * @brief 清理已完成/超时/取消的请求，释放内存
 */
void dc_async_cleanup(void)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    dc_async_request_t **pp = &g_async_queue.head;

    while (*pp)
    {
        dc_async_request_t *req = *pp;

        if (req->result_code != 0)
        {
            *pp = req->next;
            g_async_queue.req_map.erase(req->request_id);

            if (req->p_select_data)
            {
                dc_util_destroy_data(req->p_select_data, req->data_type);
            }

            if (req->p_direct_data)
            {
                dc_util_destroy_data(req->p_direct_data, req->data_type);
            }

            delete req;
            g_async_queue.count--;
        }
        else
        {
            pp = &req->next;
        }
    }
}

/**
 * @brief 获取当前 pending 请求数量
 * @return pending 请求数
 */
int dc_async_pending_count(void)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    return g_async_queue.count;
}

/**
 * @brief 设置全局默认超时时间
 * @param ms 超时毫秒数
 */
void dc_async_set_default_timeout(uint32_t ms)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    g_async_queue.default_timeout_ms = ms;
}

/**
 * @brief 设置遥控（yk）默认超时时间
 * @param ms 超时毫秒数
 */
void dc_async_set_timeout_yk(uint32_t ms)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    g_async_queue.default_timeout_yk_ms = ms;
}

/**
 * @brief 设置 AO 默认超时时间
 * @param ms 超时毫秒数
 */
void dc_async_set_timeout_ao(uint32_t ms)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    g_async_queue.default_timeout_ao_ms = ms;
}

/**
 * @brief 设置参数（param）默认超时时间
 * @param ms 超时毫秒数
 */
void dc_async_set_timeout_param(uint32_t ms)
{
    std::lock_guard<std::mutex> lk(g_async_queue.mtx);

    g_async_queue.default_timeout_param_ms = ms;
}
