/** @file dc_signal_check.cpp — 控制校验 + 值校验 */
#include "dc_internal.h"

/** @brief 校验直控值是否与选控暂存值一致 (char 数组用 strcmp) */
int dc_check_ctrl_val_valid(const dc_ctrl_t *ctrl, const void *p_data)
{
    /* 字符串类型用 strcmp 而非 memcmp, 避免尾部垃圾字节误判 */
    if (ctrl->data_type == DATA_TYPE_C8 ||
        ctrl->data_type == DATA_TYPE_C32 ||
        ctrl->data_type == DATA_TYPE_C64 ||
        ctrl->data_type == DATA_TYPE_C128 ||
        ctrl->data_type == DATA_TYPE_STR)
    {
        if (0 != strcmp((const char *)ctrl->p_data, (const char *)p_data))
        {
            LOG_E("direct val != selected val\n");
            return DC_ERR_VAL;
        }
        return DC_OK;
    }

    uint8_t len = dc_util_type_len(ctrl->data_type);

    if (!len)
    {
        return DC_ERR_TYPE;
    }

    if (0 != memcmp(ctrl->p_data, p_data, len))
    {
        LOG_E("direct val != selected val\n");
        return DC_ERR_VAL;
    }

    return DC_OK;
}

/** @brief SBO 选控-直控-撤销完整流程校验 */
int dc_check_ctrl_valid(const dc_signal_t *ps, dc_ctrl_step_t step,
    dc_ctrl_t *ctrl, const void *p_data)
{
    if (ps->data_type != ctrl->data_type)
    {
        LOG_E("type mismatch %d!=%d\n", ps->data_type, ctrl->data_type);
        return DC_ERR_TYPE;
    }

    if (ctrl->type == DC_CTRL_DIRECT)
    {
        if (step == DC_STEP_DIRECT)
        {
            return DC_OK;
        }
        return DC_ERR_STEP;
    }

    if (ctrl->type == DC_CTRL_SBO)
    {
        if (ctrl->step == DC_STEP_READY && step == DC_STEP_SELECT)
        {
            return DC_OK;
        }

        if (ctrl->step == DC_STEP_SELECT)
        {
            if (step == DC_STEP_DIRECT)
            {
                return dc_check_ctrl_val_valid(ctrl, p_data);
            }

            if (step == DC_STEP_CANCEL)
            {
                return DC_OK;
            }
        }
    }

    LOG_E("invalid ctrl type=%d step=%d\n", ctrl->type, step);

    return DC_ERR_STEP;
}

/** @brief 校验新值 (变更检测 + 范围校验 + bool 校验) */
int dc_check_val_valid(const dc_signal_t *ps, uint8_t zone, const void *p_data)
{
	if (zone >= (uint8_t)ps->vec_p_data_count)
	{
		LOG_E("zone %d out of range\n", zone);
		return DC_ERR_PARAM;
	}

	const void *cur = ps->vec_p_data[zone];

	/* 变更检测 */
	if (0 == dc_util_val_compare(ps->data_type, cur, p_data))
	{
		LOG_E("val not changed\n");
		return DC_ERR_VAL;
	}

	/* 范围校验 (基于 param.min / param.max) */
	if (ps->data_type == DATA_TYPE_B)
	{
		uint8_t b = *(const uint8_t *)p_data;

		if (b != 0 && b != 1)
		{
			LOG_E("invalid bool value %d\n", b);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_S8)
	{
		int8_t val = *(const int8_t *)p_data;

		if (val < (int8_t)ps->param.min || val > (int8_t)ps->param.max)
		{
			LOG_E("invalid s8 %d, range [%d,%d]\n", val, (int)ps->param.min, (int)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_U8)
	{
		uint8_t val = *(const uint8_t *)p_data;

		if (val < ps->param.min || val > ps->param.max)
		{
			LOG_E("invalid u8 %u, range [%u,%u]\n", val, (unsigned)ps->param.min, (unsigned)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_S16)
	{
		int16_t val = *(const int16_t *)p_data;

		if (val < (int16_t)ps->param.min || val > (int16_t)ps->param.max)
		{
			LOG_E("invalid s16 %d, range [%d,%d]\n", val, (int)ps->param.min, (int)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_U16)
	{
		uint16_t val = *(const uint16_t *)p_data;

		if (val < ps->param.min || val > ps->param.max)
		{
			LOG_E("invalid u16 %u, range [%u,%u]\n", val, (unsigned)ps->param.min, (unsigned)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_S32)
	{
		int32_t val = *(const int32_t *)p_data;

		if (val < (int32_t)ps->param.min || val > (int32_t)ps->param.max)
		{
			LOG_E("invalid s32 %d, range [%d,%d]\n", val, (int)ps->param.min, (int)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_U32)
	{
		uint32_t val = *(const uint32_t *)p_data;

		if (val < (uint32_t)ps->param.min || val > (uint32_t)ps->param.max)
		{
			LOG_E("invalid u32 %u, range [%u,%u]\n", val, (unsigned)ps->param.min, (unsigned)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_L64)
	{
		int64_t val = *(const int64_t *)p_data;

		if (val < (int64_t)ps->param.min || val > (int64_t)ps->param.max)
		{
			LOG_E("invalid l64 %lld, range [%lld,%lld]\n", val, (long long)ps->param.min, (long long)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_UL64)
	{
		uint64_t val = *(const uint64_t *)p_data;

		if (val < (uint64_t)ps->param.min || val > (uint64_t)ps->param.max)
		{
			LOG_E("invalid ul64 %llu, range [%llu,%llu]\n", val, (unsigned long long)ps->param.min, (unsigned long long)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_F32)
	{
		float val = *(const float *)p_data;

		if (val < (float)ps->param.min || val > (float)ps->param.max)
		{
			LOG_E("invalid f32 %f, range [%f,%f]\n", val, (float)ps->param.min, (float)ps->param.max);
			return DC_ERR_VAL;
		}
	}
	else if (ps->data_type == DATA_TYPE_D64)
	{
		double val = *(const double *)p_data;

		if (val < (double)ps->param.min || val > (double)ps->param.max)
		{
			LOG_E("invalid d64 %f, range [%f,%f]\n", val, (double)ps->param.min, (double)ps->param.max);
			return DC_ERR_VAL;
		}
	}

	return DC_OK;
}

/** @brief 校验遥控值有效性（仅允许 0/1） */
int dc_check_yk_val_valid(dc_signal_t *ps, void *p_data)
{
    if (ps->data_type == DATA_TYPE_B || ps->data_type == DATA_TYPE_U8)
    {
        uint8_t v = *(uint8_t *)p_data;

        if (v != 0 && v != 1)
        {
            LOG_E("invalid yk val %d\n", v);
            return DC_ERR_VAL;
        }

        return DC_OK;
    }

    return DC_ERR_TYPE;
}
