#include <mutex>
#include <sstream>
#include <tuple>
#include <map>
#include <iostream>
#include <iomanip>

#include "dc_signal.h"
#include "myLog.h"
#include "mySystem.h"
#include "myCmd.h"

struct XXH128Hash {
    size_t operator()(const XXH128_hash_t& h) const noexcept {
        // 低版本库无XXH3_64bits_fromCanonical，手动混合高低64位生成哈希
        // 采用经典的混合算法，减少哈希冲突概率
        const uint64_t mix1 = h.low64 ^ (h.high64 << 17);
        const uint64_t mix2 = mix1 + (h.high64 >> 13);
        const uint64_t mix3 = mix2 ^ (h.low64 << 23);
        // 转size_t（兼容32/64位系统）
        return static_cast<size_t>(mix3 ^ (mix3 >> 32));
    }
};

struct XXH128Equal {
    bool operator()(const XXH128_hash_t& a, const XXH128_hash_t& b) const noexcept {
        // 优先用库自带的相等判断（v0.8.0+有），没有则手动比较
        #ifdef XXH128_isEqual
            return XXH128_isEqual(a, b);
        #else
            return (a.high64 == b.high64) && (a.low64 == b.low64);
        #endif
    }
};

typedef std::unordered_map<XXH128_hash_t, stru_signal, XXH128Hash, XXH128Equal> hash_signal_map;


typedef struct
{
    std::mutex mtx;
    hash_signal_map map_signals;
    std::unordered_map<XXH128_hash_t, std::vector<stru_signal*>, XXH128Hash, XXH128Equal> hash_conflict_table;
    std::unordered_map<XXH128_hash_t, std::string, XXH128Hash, XXH128Equal> hash_index;
    std::unordered_map<XXH128_hash_t, std::vector<std::string>, XXH128Hash, XXH128Equal> hash_conflicts;
}stru_signal_map;


typedef struct
{
    stru_signal_map signal_out;
    stru_signal_map signal_in;
    stru_signal_map siganl_yk;
    stru_signal_map siganl_param;
}stru_datacenter;


static stru_datacenter g_datacenter;

LOCAL int dc_set_signal_val(void *p_data, uint8_t data_type, void *set_data);
LOCAL stru_signal* dc_find_signal(const XXH128_hash_t &hash, stru_signal_map &dc_signal_map);
LOCAL int dc_signal_add_to_map(stru_signal &signal, stru_signal_map &dc_signal_map);
LOCAL stru_signal* dc_find_out_signal(const std::string &saddr);
LOCAL stru_signal* dc_find_in_signal(const std::string &saddr);

int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data)
{
    stru_signal *p_signal = dc_find_out_signal(saddr);
    if(p_signal == nullptr)
    {
        MY_LOG_E("saddr %s not found", saddr.c_str());
        return -1;
    }

    desc = p_signal->desc;
    data_type = p_signal->data_type;
    (*p_data) = p_signal->p_data;

    return 0;
}

int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data)
{
    stru_signal *p_signal = dc_find_in_signal(saddr);
    if(p_signal == nullptr)
    {
        MY_LOG_E("saddr %s not found", saddr.c_str());
        return -1;
    }

    desc = p_signal->desc;
    data_type = p_signal->data_type;
    (*p_data) = p_signal->p_data;

    return 0;
}

int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param &param, uint8_t &ctrl_type, void **p_data)
{
    stru_signal *p_signal = dc_find_signal(XXH3_128bits(saddr.c_str(), saddr.length()), g_datacenter.siganl_param);
    if(p_signal == nullptr)
    {
        MY_LOG_E("saddr %s not found", saddr.c_str());
        return -1;
    }
    desc = p_signal->desc;
    data_type = p_signal->data_type;
    param.min = p_signal->param.min;
    param.max = p_signal->param.max;
    param.step = p_signal->param.step;
    param.unit = p_signal->param.unit;
    if(NULL != param.p_default && NULL != p_signal->param.p_default)
    {
        dc_set_signal_val(param.p_default, data_type, p_signal->param.p_default);
    }
    ctrl_type = p_signal->ctrl.type;
    (*p_data) = p_signal->p_data;

    return 0;
}

int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, uint8_t &ctrl_type, void **p_data)
{
    stru_signal *p_signal = dc_find_signal(XXH3_128bits(saddr.c_str(), saddr.length()), g_datacenter.siganl_yk);
    if(p_signal == nullptr)
    {
        MY_LOG_E("saddr %s not found", saddr.c_str());
        return -1;
    }
    desc = p_signal->desc;
    data_type = p_signal->data_type;
    ctrl_type = p_signal->ctrl.type;
    (*p_data) = p_signal->p_data;

    return 0;
}



LOCAL void dc_update_global_index(const stru_signal &signal, stru_signal_map &dc_signal_map)
{
    auto it = dc_signal_map.hash_index.find(signal.hash);
    if(it != dc_signal_map.hash_index.end())
    {
        if(it->second != signal.saddr)
        {
            MY_LOG_E("hash collision: %s -> %s", it->second.c_str(), signal.saddr.c_str());
            dc_signal_map.hash_conflicts[signal.hash].push_back(it->second);
            dc_signal_map.hash_conflicts[signal.hash].push_back(signal.saddr);
        }
    }
    else
    {
        dc_signal_map.hash_index.emplace(signal.hash, signal.saddr);
    }
}


LOCAL int dc_signal_add_to_map(stru_signal &signal, stru_signal_map &dc_signal_map)
{
    std::lock_guard<std::mutex> lock(dc_signal_map.mtx);

    hash_signal_map &signal_map = dc_signal_map.map_signals;
    auto conflict_it = dc_signal_map.hash_conflict_table.find(signal.hash);
    if (conflict_it != dc_signal_map.hash_conflict_table.end()) 
    {
        for(stru_signal *exist_signal : conflict_it->second)
        {
            if(exist_signal->saddr == signal.saddr)
            {
                *exist_signal = signal;
                return 0;
            }
        }

        stru_signal new_signal = signal;
        conflict_it->second.push_back(&new_signal);
    }
    else
    {
        auto map_it = signal_map.find(signal.hash);
        if(map_it != signal_map.end())
        {
            if(map_it->second.saddr != signal.saddr)
            {
                std::vector<stru_signal*> conficts;
                conficts.push_back(&map_it->second);
                conficts.push_back(&signal);
                dc_signal_map.hash_conflict_table[signal.hash] = conficts;
            }
            else
            {
                map_it->second = signal;
            }
        }
        else
        {
            signal_map.emplace(signal.hash, signal);
        }
    }
        
    dc_update_global_index(signal, dc_signal_map);

    return 0;
}


int dc_signal_out(const std::string &saddr, const std::string &desc, uint8_t data_type, void *p_data)
{
    stru_signal signal;

    signal.hash = XXH3_128bits(saddr.c_str(), saddr.length());
    signal.saddr.assign(saddr);
    signal.desc.assign(desc);
    signal.data_type = data_type;
    signal.p_data = p_data;

    // MY_LOG_I("saddr %s, p_data %p", saddr.c_str(), p_data);
    return dc_signal_add_to_map(signal, g_datacenter.signal_out);
}


int dc_signal_in(const std::string &saddr, const std::string &desc, const std::string &link_saddr, uint8_t data_type, void **p_data)
{
    stru_signal signal;

    signal.hash = XXH3_128bits(saddr.c_str(), saddr.length());
    signal.saddr.assign(saddr);
    signal.desc.assign(desc);
    signal.data_type = data_type;
    
    if(link_saddr.empty())
    {
        MY_LOG_E("link_saddr is empty");
        return -1;
    }

    stru_signal *p_signal_out = dc_find_out_signal(link_saddr);
    if(p_signal_out == nullptr)
    {
        MY_LOG_E("link_saddr %s not found", link_saddr.c_str());
        return -1;
    }
    
    (*p_data) = p_signal_out->p_data;
    signal.p_data = (*p_data);

    bool found = false;
    for(auto it = p_signal_out->link_saddrs.begin(); it != p_signal_out->link_saddrs.end(); ++it)
    {
        if(it->compare(saddr) == 0)
        {
            found = true;
            break;
        }
    }

    if(!found)
    {
        p_signal_out->link_saddrs.push_back(saddr);
    }

    signal.link_saddrs.push_back(link_saddr);

    MY_LOG_I("saddr %s, p_data %p, link_saddr %s", saddr.c_str(), (*p_data), link_saddr.c_str());

    return dc_signal_add_to_map(signal, g_datacenter.signal_in);
}

LOCAL void dc_signal_ctrl_data_create(stru_signal_ctrl &ctrl)
{
    switch(ctrl.data_type)
    {
        case DATA_TYPE_B:
        case DATA_TYPE_U8:
            ctrl.p_data = new uint8_t;
            *(uint8_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_S8:
            ctrl.p_data = new int8_t;
            *(int8_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_S16:
            ctrl.p_data = new int16_t;
            *(int16_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_U16:
            ctrl.p_data = new uint16_t;
            *(uint16_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_S32:
            ctrl.p_data = new int32_t;
            *(int32_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_U32:
            ctrl.p_data = new uint32_t;
            *(uint32_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_L64:
            ctrl.p_data = new int64_t;
            *(int64_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_UL64:
            ctrl.p_data = new uint64_t;
            *(uint64_t *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_F32:
            ctrl.p_data = new float;
            *(float *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_D64:
            ctrl.p_data = new double;
            *(double *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_IP:
            ctrl.p_data = new char[4];
            memset(ctrl.p_data, 0, 4);
            break;
        case DATA_TYPE_MAC:
            ctrl.p_data = new char[8];
            memset(ctrl.p_data, 0, 8);
            break;
        case DATA_TYPE_C1:
            ctrl.p_data = new char;
            *(char *)ctrl.p_data = 0;
            break;
        case DATA_TYPE_C8:
            ctrl.p_data = new char[8];
            memset(ctrl.p_data, 0, 8);
            break;
        case DATA_TYPE_C32:
            ctrl.p_data = new char[32];
            memset(ctrl.p_data, 0, 32);
            break;
        case DATA_TYPE_C64:
            ctrl.p_data = new char[64];
            memset(ctrl.p_data, 0, 64);
            break;
        case DATA_TYPE_C128:
            ctrl.p_data = new char[128];
            memset(ctrl.p_data, 0, 128);
            break;
        default:
            LOG_E("unsupported data type %d", ctrl.data_type);
            break;
    }
}

int dc_signal_param(const std::string &saddr, const std::string &desc, uint8_t data_type, const stru_signal_param &param, uint8_t ctrl_type, void *p_data, signal_change_cb cb)
{
    // 先从参数表里解析，调用参数注册
    // 程序注册时，从参数表里去查找，同一个信息，使用参数表中的保存的数据值，在线程初始化时，通知所有链接此信号的信号
    // 注册时不在参数表中的，新增到动态表里，并保存到参数表里，使用缺省值

    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
    stru_signal *p_signal = dc_find_signal(hash, g_datacenter.siganl_param);
    if(p_signal != nullptr)
    {
        dc_set_signal_val(p_data, data_type, p_signal->p_data);
        p_signal->change_cb_list.push_back(cb);
        return 0;
    }

    stru_signal signal;
    signal.hash = hash;
    signal.saddr.assign(saddr);
    signal.desc.assign(desc);
    signal.data_type = data_type;
    signal.p_data = p_data;
    signal.param = param;

    dc_signal_add_to_map(signal, g_datacenter.siganl_param);

    p_signal = dc_find_signal(hash, g_datacenter.siganl_param);
    if(p_signal != nullptr)
    {
        if(cb)
        {
            p_signal->change_cb_list.push_back(cb);
        }

        p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
        p_signal->ctrl.type = ctrl_type;
        p_signal->ctrl.data_type = data_type;
        dc_signal_ctrl_data_create(p_signal->ctrl);

        return 0;
    }

    return -1;
}

int dc_signal_param_link_with_callback(const std::string &saddr, uint8_t data_type, void **p_data, signal_change_cb cb)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
    stru_signal *p_signal = dc_find_signal(hash, g_datacenter.siganl_param);
    if(p_signal != nullptr)
    {
        if(p_signal->data_type != data_type)
        {
            LOG_E("saddr %s data type %s(%d) not match %s(%d)", 
                saddr.c_str(), dc_get_data_type_str_by_id(p_signal->data_type), p_signal->data_type, dc_get_data_type_str_by_id(data_type), data_type);
            return -1;
        }
        
        if(cb)
        {
            p_signal->change_cb_list.push_back(cb);
        }
        (*p_data) = p_signal->p_data;
        return 0;
    }

    return -1;
}

LOCAL int dc_check_ctrl_val_valid(const stru_signal_ctrl &ctrl, const void *p_data)
{
    if(ctrl.data_type == DATA_TYPE_B || ctrl.data_type == DATA_TYPE_U8)
    {
        if(*(uint8_t *)p_data != *(uint8_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(uint8_t*)p_data, *(uint8_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_S8)
    {
        if(*(int8_t *)p_data != *(int8_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(int8_t*)p_data, *(int8_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_S16)
    {
        if(*(int16_t *)p_data != *(int16_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(int16_t*)p_data, *(int16_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_U16)
    {
        if(*(uint16_t *)p_data != *(uint16_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(uint16_t*)p_data, *(uint16_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_S32)
    {
        if(*(int32_t *)p_data != *(int32_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(int32_t*)p_data, *(int32_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_U32)
    {
        if(*(uint32_t *)p_data != *(uint32_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %d not match selected value %d", *(uint32_t*)p_data, *(uint32_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_L64)
    {
        if(*(int64_t *)p_data != *(int64_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %lld not match selected value %lld", *(int64_t*)p_data, *(int64_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_UL64)
    {
        if(*(uint64_t *)p_data != *(uint64_t *)ctrl.p_data)
        {
            LOG_E("direct ctrl value %lld not match selected value %lld", *(uint64_t*)p_data, *(uint64_t*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_F32)
    {
        if(*(float*)p_data != *(float*)ctrl.p_data)
        {
            LOG_E("direct ctrl value %f not match selected value %f", *(float*)p_data, *(float*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_D64)
    {
        if(*(double*)p_data != *(double*)ctrl.p_data)
        {
            LOG_E("direct ctrl value %lf not match selected value %lf", *(double*)p_data, *(double*)ctrl.p_data);
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_IP)
    {
        if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 4));
        {
            LOG_E("direct ctrl value %s not match selected value %s", 
                dc_get_signal_val(ctrl.p_data, DATA_TYPE_IP).c_str(), dc_get_signal_val((char *)p_data, DATA_TYPE_IP).c_str());
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_MAC)
    {
        if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 6));
        {
            LOG_E("direct ctrl value %s not match selected value %s", 
                dc_get_signal_val(ctrl.p_data, DATA_TYPE_MAC).c_str(), dc_get_signal_val((char *)p_data, DATA_TYPE_MAC).c_str());
            return -1;
        }
    }
    else if(ctrl.data_type == DATA_TYPE_C1)
    {
        if(*(char*)p_data != *(char*)ctrl.p_data)
        {
            LOG_E("direct ctrl value %c not match selected value %c", *(char*)p_data, *(char*)ctrl.p_data);
            return -1;
        }
    }else 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)
    {
        if(0 != strcmp((char *)ctrl.p_data, (char *)p_data))
        {
            LOG_E("direct ctrl value %s not match selected value %s", (char *)ctrl.p_data, (char *)p_data);
            return -1;
        }
    }
    // else if(ctrl.data_type == DATA_TYPE_C8)
    // {
    //     if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 8));
    //     {
    //         LOG_E("direct ctrl value %s not match selected value %s", (char *)ctrl.p_data, (char *)p_data);
    //         return -1;
    //     }
    // }
    // else if(ctrl.data_type == DATA_TYPE_C32)
    // {
    //     if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 32));
    //     {
    //         LOG_E("direct ctrl value %s not match selected value %s", (char *)ctrl.p_data, (char *)p_data);
    //         return -1;
    //     }
    // }
    // else if(ctrl.data_type == DATA_TYPE_C64)
    // {
    //     if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 64));
    //     {
    //         LOG_E("direct ctrl value %s not match selected value %s", (char *)ctrl.p_data, (char *)p_data);
    //         return -1;
    //     }
    // }
    // else if(ctrl.data_type == DATA_TYPE_C128)
    // {
    //     if(0 != memcmp((char *)ctrl.p_data, (char *)p_data, 128));
    //     {
    //         LOG_E("direct ctrl value %s not match selected value %s", (char *)ctrl.p_data, (char *)p_data);
    //         return -1;
    //     }
    // }
    else
    {
        LOG_E("invalid ctrl data_type %d", ctrl.data_type);
        return -1;
    }

    return 0;
}

LOCAL int dc_check_ctrl_valid(const stru_signal *p_signal, SIGNAL_CTRL_STEP step, uint8_t data_type, const void *p_data)
{
    // LOG_I("dc_check_ctrl_valid %s, step %d, data_type %d, p_data %d", p_signal->saddr.c_str(), step, data_type, *(uint8_t *)p_data);

    if(p_signal->data_type != data_type)
    {
        LOG_E("%s data_type %d not match ctrl data_type %d", p_signal->saddr.c_str(), p_signal->data_type, data_type);
        return -1;
    }

    if(p_signal->ctrl.type == SIGNAL_CTRL_TYPE::DIRECT_NORMAL)
    {
        if(step == SIGNAL_CTRL_STEP::DIRECT)
        {
            return 0;
        }
        else
        {
            LOG_E("%s ctrl_type %d, invalid ctrl step %d", p_signal->saddr.c_str(), p_signal->ctrl.type, step);
            return -1;
        }
    }
    else if(p_signal->ctrl.type == SIGNAL_CTRL_TYPE::SBO_NORMAL)
    {
        if(p_signal->ctrl.step == SIGNAL_CTRL_STEP::READY)
        {
            if(step == SIGNAL_CTRL_STEP::SELECT)
            {
                return 0;
            }
            else
            {
                LOG_E("%s ctrl_type %d, invalid ctrl step %d", p_signal->saddr.c_str(), p_signal->ctrl.type, step);
                return -1;
            }
        }
        else if(p_signal->ctrl.step == SIGNAL_CTRL_STEP::SELECT)
        {
            if(step == SIGNAL_CTRL_STEP::DIRECT)
            {
                if(0 == dc_check_ctrl_val_valid(p_signal->ctrl, p_data))
                {
                    return 0;
                }
                else
                {
                    LOG_E("%s ctrl_type %d, direct value not match selected value", p_signal->saddr.c_str(), p_signal->ctrl.type);  
                    return -1;
                }
            }
            else if(step == SIGNAL_CTRL_STEP::CANCEL)
            {
                return 0;
            }
            else
            {
                LOG_E("%s ctrl_type %d, invalid ctrl step %d", p_signal->saddr.c_str(), p_signal->ctrl.type, step);
                return -1;
            }
        }
    }

    LOG_E("invalid ctrl type %d", p_signal->ctrl.type);
    return -1;
}


LOCAL int dc_check_val_valid(const stru_signal *p_signal, const void *p_data)
{
    stru_signal_param param = p_signal->param;

    if(p_signal->data_type == DATA_TYPE_B)
    {
        if(*(uint8_t *)p_signal->p_data == *(uint8_t *)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(uint8_t*)p_signal->p_data);
            return -1;
        }

        uint8_t b = *(uint8_t*)p_data;
        if(b != 0 && b != 1)
        {
            LOG_E("invalid bool value %d", b);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_S8)
    {
        if(*(int8_t*)p_signal->p_data == *(int8_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(int8_t*)p_signal->p_data);
            return -1;
        }

        int8_t s8 = *(int8_t*)p_data;
        if(s8 < (int8_t)param.min || s8 > (int8_t)param.max)
        {
            LOG_E("invalid int8_t value %d, range [%d, %d]", s8, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_U8)
    {
        if(*(uint8_t*)p_signal->p_data == *(uint8_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(uint8_t*)p_signal->p_data);
            return -1;
        }

        uint8_t u8 = *(uint8_t*)p_data;
        if(u8 < param.min || u8 > param.max)
        {
            LOG_E("invalid uint8_t value %d, range [%d, %d]", u8, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_S16)
    {
        if(*(int16_t*)p_signal->p_data == *(int16_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(int16_t*)p_signal->p_data);
            return -1;
        }

        int16_t s16 = *(int16_t*)p_data;
        if(s16 < (int16_t)param.min || s16 > (int16_t)param.max)
        {
            LOG_E("invalid int16_t value %d, range [%d, %d]", s16, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_U16)
    {
        if(*(uint16_t*)p_signal->p_data == *(uint16_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(uint16_t*)p_signal->p_data);
            return -1;
        }

        uint16_t u16 = *(uint16_t*)p_data;
        if(u16 < param.min || u16 > param.max)
        {
            LOG_E("invalid uint16_t value %d, range [%d, %d]", u16, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_S32)
    {
        if(*(int32_t*)p_signal->p_data == *(int32_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(int32_t*)p_signal->p_data);
            return -1;
        }

        int32_t s32 = *(int32_t*)p_data;
        if(s32 < (int32_t)param.min || s32 > (int32_t)param.max)
        {
            LOG_E("invalid int32_t value %d, range [%d, %d]", s32, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_U32)
    {
        if(*(uint32_t*)p_signal->p_data == *(uint32_t*)p_data)
        {
            LOG_E("%s value %d not changed", p_signal->saddr.c_str(), *(uint32_t*)p_signal->p_data);
            return -1;
        }

        uint32_t u32 = *(uint32_t*)p_data;
        if(u32 < param.min || u32 > param.max)
        {
            LOG_E("invalid uint32_t value %d, range [%d, %d]", u32, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_L64)
    {
        if(*(int64_t*)p_signal->p_data == *(int64_t*)p_data)
        {
            LOG_E("%s value %lld not changed", p_signal->saddr.c_str(), *(int64_t*)p_signal->p_data);
            return -1;
        }

        int64_t l64 = *(int64_t*)p_data;
        if(l64 < (int64_t)param.min || l64 > (int64_t)param.max)
        {
            LOG_E("invalid int64_t value %lld, range [%lld, %lld]", l64, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_UL64)
    {
        if(*(uint64_t*)p_signal->p_data == *(uint64_t*)p_data)
        {
            LOG_E("%s value %llu not changed", p_signal->saddr.c_str(), *(uint64_t*)p_signal->p_data);
            return -1;
        }

        uint64_t ul64 = *(uint64_t*)p_data;
        if(ul64 < param.min || ul64 > param.max)
        {
            LOG_E("invalid uint64_t value %llu, range [%llu, %llu]", ul64, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_F32)
    {
        if(*(float*)p_signal->p_data == *(float*)p_data)
        {
            LOG_E("%s value %f not changed", p_signal->saddr.c_str(), *(float*)p_signal->p_data);
            return -1;
        }

        float f32 = *(float*)p_data;
        if(f32 < (float)param.min || f32 > (float)param.max)
        {
            LOG_E("invalid float value %f, range [%f, %f]", f32, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_D64)
    {
        if(*(double*)p_signal->p_data == *(double*)p_data)
        {
            LOG_E("%s value %f not changed", p_signal->saddr.c_str(), *(double*)p_signal->p_data);
            return -1;
        }

        double d64 = *(double*)p_data;
        if(d64 < (double)param.min || d64 > (double)param.max)
        {
            LOG_E("invalid double value %f, range [%f, %f]", d64, param.min, param.max);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_IP)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 4))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_MAC)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 6))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_C8)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 8))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_C32)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 32))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_C64)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 64))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_C128)
    {
        if(0 == memcmp((char *)p_signal->p_data, (char *)p_data, 128))
        {
            LOG_E("%s value %s not changed", p_signal->saddr.c_str(), (char*)p_signal->p_data);
            return -1;
        }
    }
    else if(p_signal->data_type == DATA_TYPE_C1)
    {
        if(*(char*)p_signal->p_data == *(char*)p_data)
        {
            LOG_E("%s value %c not changed", p_signal->saddr.c_str(), *(char*)p_signal->p_data);
            return -1;
        }
    }
    else
    {
        LOG_E("data_type is not valid: %d", p_signal->data_type);
        return -1;
    }

    return 0;
}

int dc_signal_param_set_val(const std::string &saddr, SIGNAL_CTRL_STEP step, uint8_t data_type, void *p_data)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
    stru_signal *p_signal = dc_find_signal(hash, g_datacenter.siganl_param);
    if(p_signal != nullptr) 
    {
        if(0 == dc_check_ctrl_valid(p_signal, step, data_type, p_data))
        {
            if(0 != dc_check_val_valid(p_signal, p_data))
            {
                LOG_E("set value failed, saddr: %s", saddr.c_str());
                return -1;
            }

            if(step == SIGNAL_CTRL_STEP::SELECT)
            {
                dc_set_signal_val(p_signal->ctrl.p_data, data_type, p_data);
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::SELECT;
            }
            else if(step == SIGNAL_CTRL_STEP::DIRECT)
            {
                dc_set_signal_val(p_signal->p_data, data_type, p_data);
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            }
            else if(step == SIGNAL_CTRL_STEP::CANCEL)
            {
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            }
            else
            {
                LOG_E("invalid ctrl step %d", step);
                return -1;
            }

            for(auto cb : p_signal->change_cb_list)
            {
                if(cb != nullptr)
                {
                    cb(saddr, step, data_type, p_data);
                }
            }
            return 0;
        }
        else
        {
            LOG_E("set ctrl failed, saddr: %s", saddr.c_str());
            p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            return -1;
        }
    }

    LOG_E("saddr %s not found in param table");
    return -1;
}


int dc_signal_yk(const std::string &saddr, const std::string &desc, uint8_t data_type, uint8_t ctrl_type, void *p_data, signal_change_cb cb)
{
    stru_signal signal;

    signal.hash = XXH3_128bits(saddr.c_str(), saddr.length());
    signal.saddr.assign(saddr);
    signal.desc.assign(desc);
    signal.data_type = data_type;
    signal.p_data = p_data;

    dc_signal_add_to_map(signal, g_datacenter.siganl_yk);

    stru_signal *p_signal = dc_find_signal(signal.hash, g_datacenter.siganl_yk);
    if(p_signal != nullptr)
    {
        if(cb)
        {
            p_signal->change_cb_list.push_back(cb);
        }

        p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
        p_signal->ctrl.type = ctrl_type;
        p_signal->ctrl.data_type = data_type;
        dc_signal_ctrl_data_create(p_signal->ctrl);

        return 0;
    }

    return -1;
}

int dc_signal_yk_link_with_callback(const std::string &saddr, uint8_t data_type, void **p_data, signal_change_cb cb)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
    stru_signal *p_signal = dc_find_signal(hash, g_datacenter.siganl_yk);
    if(p_signal != nullptr)
    {
        if(cb)
        {
            p_signal->change_cb_list.push_back(cb);
        }
        (*p_data) = p_signal->p_data;
        return 0;
    }

    return -1;
}

int dc_signal_yk_set_status(const std::string &saddr, SIGNAL_CTRL_STEP step, uint8_t data_type, void *p_data)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
    stru_signal *p_signal = dc_find_signal(hash, g_datacenter.siganl_yk);
    if(p_signal != nullptr)
    {
        if(0 == dc_check_ctrl_valid(p_signal, step, data_type, p_data))
        {
            if(step == SIGNAL_CTRL_STEP::SELECT)
            {
                dc_set_signal_val(p_signal->ctrl.p_data, data_type, p_data);
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::SELECT;
            }
            else if(step == SIGNAL_CTRL_STEP::DIRECT)
            {
                dc_set_signal_val(p_signal->p_data, data_type, p_data);
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            }
            else if(step == SIGNAL_CTRL_STEP::CANCEL)
            {
                p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            }
            else
            {
                LOG_E("invalid ctrl step %d", step);
                return -1;
            }

            for(auto cb : p_signal->change_cb_list)
            {
                if(cb != nullptr)
                {
                    cb(saddr, step, data_type, p_data);
                }
            }
            return 0;
        }
        else
        {
            LOG_E("set ctrl failed, saddr: %s", saddr.c_str());
            p_signal->ctrl.step = SIGNAL_CTRL_STEP::READY;
            return -1;
        }
    }

    LOG_E("saddr %s not found in yk table");
    return -1;
}


LOCAL stru_signal* dc_find_signal(const XXH128_hash_t &hash, stru_signal_map &dc_signal_map)
{
    std::lock_guard<std::mutex> lock(dc_signal_map.mtx);

    hash_signal_map &signal_map = dc_signal_map.map_signals;
    auto map_it = signal_map.find(hash);
    if(map_it != signal_map.end())
    {
        return &map_it->second;
    }
    else
    {
        return nullptr;
    }
}


LOCAL stru_signal* dc_find_out_signal(const std::string &saddr)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());

    return dc_find_signal(hash, g_datacenter.signal_out);
}

LOCAL stru_signal* dc_find_in_signal(const std::string &saddr)
{
    XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());

    return dc_find_signal(hash, g_datacenter.signal_in);
}

LOCAL std::map<uint8_t, std::string> g_data_type_str = {
    {DATA_TYPE_B, "bool"},
    {DATA_TYPE_S8, "int8_t"},
    {DATA_TYPE_U8, "uint8_t"},
    {DATA_TYPE_S16, "int16_t"},
    {DATA_TYPE_U16, "uint16_t"},
    {DATA_TYPE_S32, "int32_t"},
    {DATA_TYPE_U32, "uint32_t"},
    {DATA_TYPE_L64, "int64_t"},
    {DATA_TYPE_UL64, "uint64_t"},
    {DATA_TYPE_F32, "float"},
    {DATA_TYPE_D64, "double"},
    {DATA_TYPE_IP, "ip"},
    {DATA_TYPE_MAC, "mac"},
    {DATA_TYPE_C8, "char8"},
    {DATA_TYPE_C32, "char32"},
    {DATA_TYPE_C64, "char64"},
    {DATA_TYPE_C128, "char128"},
    {DATA_TYPE_C1, "char1"}
};

std::string dc_get_data_type_str_by_id(uint8_t data_type)
{
    auto it = g_data_type_str.find(data_type);
    if(it != g_data_type_str.end())
    {
        return it->second;
    }
    else
    {
        return "unknown";
    }
}

uint8_t dc_get_data_type_id_by_str(const std::string &data_type_str)
{
    for(const auto &p : g_data_type_str)
    {
        if(p.second.compare(data_type_str) == 0)
        {
            return p.first;
        }
    }
    return 0;
}

std::string dc_get_signal_val(void *p_data, uint8_t data_type)
{
    std::string str = "";
    char temp[32] = {0};
    char *ptr = NULL;

    switch(data_type)
    {
        case DATA_TYPE_B:
            str = (*(int8_t *)p_data) > 0 ? "true" : "false";
            break;
        case DATA_TYPE_S8:
            str = std::to_string(*(int8_t *)p_data);
            break;
        case DATA_TYPE_U8:
            str = std::to_string(*(uint8_t*)p_data);
            break;
        case DATA_TYPE_S16:
            str = std::to_string(*(int16_t *)p_data);
            break;
        case DATA_TYPE_U16:
            str = std::to_string(*(uint16_t*)p_data);
            break;
        case DATA_TYPE_S32:
            str = std::to_string(*(int32_t *)p_data);   
            break;
        case DATA_TYPE_U32:
            str = std::to_string(*(uint32_t*)p_data);
            break;
        case DATA_TYPE_L64:
            str = std::to_string(*(int64_t *)p_data);
            break;
        case DATA_TYPE_UL64:
            str = std::to_string(*(uint64_t*)p_data);
            break;
        case DATA_TYPE_F32:
            str = std::to_string(*(float*)p_data);
            break;
        case DATA_TYPE_D64:
            str = std::to_string(*(double*)p_data);
            break;
        case DATA_TYPE_IP:
            ptr = (char *)p_data;
            snprintf(temp, 32, "%d.%d.%d.%d", (uint8_t)ptr[0], (uint8_t)ptr[1], (uint8_t)ptr[2], (uint8_t)ptr[3]);
            str = std::string(temp);
            break;
        case DATA_TYPE_MAC:
            ptr = (char *)p_data;
            snprintf(temp, 32, "%02X:%02X:%02X:%02X:%02X:%02X", (uint8_t)ptr[0], (uint8_t)ptr[1], (uint8_t)ptr[2], (uint8_t)ptr[3], (uint8_t)ptr[4], (uint8_t)ptr[5]);
            str = std::string(temp);
            break;
        case DATA_TYPE_C8:
        case DATA_TYPE_C32:
        case DATA_TYPE_C64:
        case DATA_TYPE_C128:
            str = (char *)p_data;
            break;
        case DATA_TYPE_C1:
            str = std::string(1, *(char*)p_data);
        default:
            break;
    }

    return str;
}

LOCAL int dc_set_signal_val(void *p_data, uint8_t data_type, void *set_data)
{
    if(NULL == p_data || NULL == set_data)
    {
        LOG_E("p_data or str is NULL, p_data: %p, set_data: %p", p_data, set_data);
        return -1;
    }

    switch(data_type)
    {
        case DATA_TYPE_B:
            *(int8_t *)p_data = ((char *)set_data)[0] & 0x01;
            break;
        case DATA_TYPE_S8:
            *(int8_t *)p_data = *(int8_t *)set_data;
            break;
        case DATA_TYPE_U8:
            *(uint8_t*)p_data = *(uint8_t*)set_data;
            break;
        case DATA_TYPE_S16:
            *(int16_t *)p_data = *(int16_t *)set_data;
            break;
        case DATA_TYPE_U16:
            *(uint16_t*)p_data = *(uint16_t*)set_data;
            break;
        case DATA_TYPE_S32:
            *(int32_t *)p_data = *(int32_t *)set_data;
            break;
        case DATA_TYPE_U32:
            *(uint32_t*)p_data = *(uint32_t*)set_data;
            break;
        case DATA_TYPE_L64:
            *(int64_t *)p_data = *(int64_t *)set_data;
            break;
        case DATA_TYPE_UL64:
            *(uint64_t*)p_data = *(uint64_t*)set_data;
            break;
        case DATA_TYPE_F32:
            *(float*)p_data = *(float*)set_data;
            break;
        case DATA_TYPE_D64:
            *(double*)p_data = *(double*)set_data;
            break;
        case DATA_TYPE_IP:
            strncpy((char *)p_data, (char *)set_data, 4);
            break;
        case DATA_TYPE_MAC:
            strncpy((char *)p_data, (char *)set_data, 6);
            break;
        case DATA_TYPE_C8:
        case DATA_TYPE_C32:
        case DATA_TYPE_C64:
        // case DATA_TYPE_C128:
            strncpy((char *)p_data, (char *)set_data, data_type);
            break;
        case DATA_TYPE_C1:
            *(char*)p_data = *(char*)set_data;
            break;
        default:
            LOG_E("unknown data_type: %d", data_type);
            return -1;
    }
    
    return 0;
}

int dc_set_out_signal_val(const std::string &saddr, void *set_data)
{
    stru_signal *p_signal = dc_find_out_signal(saddr);
    if(p_signal != nullptr)
    {
        return dc_set_signal_val(p_signal->p_data, p_signal->data_type, set_data);
    }

    return -1;
}



LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
{
    using namespace std;

    hash_signal_map &signal_map = dc_signal_map.map_signals;

    // 定义列宽（单位：字符，考虑中英文混合）
    const int COL_SADDR = 48;
    const int COL_DESC = 64;
    const int COL_TYPE = 12;
    const int COL_VAL = 32;
    const int COL_LINK = 64;

    // 打印表头（严格对齐，使用left对齐）
    cout << "\t"
         << left << setw(COL_SADDR) << "saddr"
         << setw(COL_DESC) << "desc"
         << setw(COL_TYPE) << "data_type"
         << setw(COL_VAL) << "val"
         << setw(COL_LINK) << "link_saddrs"
         << endl;

    // 打印分隔线（总长度 = 各列宽度之和）
    int total_width = COL_SADDR + COL_DESC + COL_TYPE + COL_VAL + COL_LINK;
    cout << "\t" << string(total_width, '-') << endl;

    // 遍历信号表
    for(auto it = signal_map.begin(); it != signal_map.end(); ++it)
    {
        const stru_signal &signal = it->second;

        // 1. 先把所有列的内容拼接成字符串，再一次性输出，避免中间打断setw对齐
        string link_str;
        bool first = true;
        for (const auto &link : signal.link_saddrs)
        {
            if (!first) link_str += ", ";
            link_str += link;
            first = false;
        }

        // 2. 输出所有列，严格使用setw控制宽度
        cout << "\t"
             << left << setw(COL_SADDR) << signal.saddr
             << setw(COL_DESC) << signal.desc
             << setw(COL_TYPE) << dc_get_data_type_str_by_id(signal.data_type)
             << setw(COL_VAL) << dc_get_signal_val(signal.p_data, signal.data_type)
             << setw(COL_LINK) << link_str
             << endl;
    }

    cout << endl;
    cout << "signal count: " << signal_map.size() << endl;
    cout << "conflict count: " << dc_signal_map.hash_conflicts.size() << endl;
    
    if(dc_signal_map.hash_conflicts.empty())
    {
        cout << "no conflict" << endl;
    }
    else
    {
        cout << "conflicts: count " << dc_signal_map.hash_conflicts.size() << endl;
        for(auto it = dc_signal_map.hash_conflicts.begin(); it != dc_signal_map.hash_conflicts.end(); ++it)
        {
            const auto &hash = it->first;
            const auto &saddrs = it->second;
            cout << "  hash: " << hash.low64 << "-" << hash.high64 << " num: " << saddrs.size() << endl;
            for(auto &saddr : saddrs)
            {
                cout << "    " << saddr.c_str() << endl;
            }
        }
    }

    cout << endl;
}

LOCAL void dc_show_out_signals()
{
    using namespace std;
    cout << "out signals: " << endl;
    dc_show_signals(g_datacenter.signal_out);
}

LOCAL void dc_show_in_signals()
{
    using namespace std;

    cout << "in signals: " << endl;
    dc_show_signals(g_datacenter.signal_in);
}

LOCAL void dc_show_yk_signals()
{
    using namespace std;

    cout << "yk signals: " << endl;
    dc_show_signals(g_datacenter.siganl_yk);
}

LOCAL void dc_show_param_signals()
{
    using namespace std;

    cout << "param signals: " << endl;
    dc_show_signals(g_datacenter.siganl_param);
}



LOCAL void cmd_dc(int argc, char *argv[])
{
    const char *str = "\
        datacenter out ----------> 查看out信号信息\n\
        datacenter in ----------> 查看in信号信息\n\
        datacenter yk ----------> 查看yk信号信息\n\
        datacenter param ----------> 查看param信号信息\n\
        datacenter all ----------> 查看所有信号信息\n";


    if(argc < 2)
    {
        printf("%s", str);
        return;
    }

    if(0 == strcmp(argv[1], "out"))
    {
        dc_show_out_signals();
    }
    else if(0 == strcmp(argv[1], "in"))
    {
        dc_show_in_signals();
    }
    else if(0 == strcmp(argv[1], "yk"))
    {
        dc_show_yk_signals();
    }
    else if(0 == strcmp(argv[1], "param"))
    {
        dc_show_param_signals();
    }
    else if(0 == strcmp(argv[1], "all"))
    {
        dc_show_out_signals();
        dc_show_in_signals();
        dc_show_yk_signals();
        dc_show_param_signals();
    }
}

CMD_REGISTER("datacenter", cmd_dc, "数据中心的控制命令");


