#include <string.h>
#include <arpa/inet.h>

#include "bms_modbus_tcp_port.h"
#include "bmser_msg_ring.h"
#include "mqtt_msg_proc.h"
#include "mosquitto.h"
#include "bms_my_log.h"
#include "bmser_mqtt.h"
#include "bmser_db_control_db.h"
#include "modbus.h"
#include "bmser_modbus_tcp_poll.h"
#include "dynamic_array.h"
#include "bmser_utils.h"
#include "bmser_dev.h"

static struct MODBUS_TCP_POLL_MQTT_MGR_S
{
    char        setTopic[MQTT_TOPIC_MAX_LEN];
    char        respTopic[MQTT_TOPIC_MAX_LEN];
    char        gwSn[64];
    char        devSn[64];
} g_mqtt_mgr;

static struct mosquitto* g_mosq = NULL;

/**
 * @brief       获取dev sn，由于bmser_dev.h中的bmser_dev_get_board_dev_sn不能用，自己定义一个
 *              直接从bmser_dev_get_board_sn返回的sn后加8个"0"
 * @param[in]   pGwSN   gw sn
 * @param[out]  pDevSN  dev sn
 * @return      操作结果
 * @retval      
 * @par         修改日志:
 * Date                Author     Description          \n
 * 2023-02-06          MXG        创建初始版本          \n
*/
static int BMS_GetDevSN(char *pGwSN, char *pDevSN)
{
    if (NULL == pGwSN || NULL == pDevSN)
    {
        BMS_MyLogError("input param is null");

        return OPRT_PARA_NULL;
    }

    strcpy(pDevSN, pGwSN);
    strcat(pDevSN, "00000000");

    return OPRT_OK;
}

static int DecodeMqttMsg(struct BMSER_MSG_RING_INFO* pMsgInfo,  \
                            const uint8_t* pBuffer, \
                            size_t size)
{
    int ret = 0;
    struct MQTT_MSG_S *pMsg = NULL;

    if (pMsg == NULL || pBuffer == NULL || size < sizeof(struct MQTT_MSG_S))
    {
        return -1;
    }

    pMsg = (struct MQTT_MSG_S *)pBuffer;
    pMsgInfo->header.func = pMsg->func;
    pMsgInfo->header.slaveID = pMsg->devId;
    pMsgInfo->header.startAddr = ntohs(pMsg->startAddr);
    pMsgInfo->header.regNum = ntohs(pMsg->regCnt);

    pMsgInfo->header.dataSize = pMsgInfo->header.regNum *   \
                                MODBUS_TCP_REG_ADDR_LEN;
    memcpy(pMsgInfo->buffer, pMsg->data, pMsgInfo->header.dataSize);

    return 0;
}

static int EncodeMqttMsg(struct BMSER_MSG_RING_INFO* pMsgInfo,  \
                            uint8_t* pBuffer)
{
    int len = 0;
    struct MQTT_MSG_S *pMsg = NULL;

    if (pBuffer == NULL)
    {
        return -1;
    }

    pMsg = (struct MQTT_MSG_S *)pBuffer;
    pMsg->func = pMsgInfo->header.func;
    pMsg->devId = pMsgInfo->header.slaveID;
    pMsg->layer = pMsgInfo->header.slaveID == 0 ? 3 : 2;
    pMsg->startAddr = htons(pMsgInfo->header.startAddr);
    pMsg->regCnt = htons(pMsgInfo->header.regNum);

    memcpy(pMsg->data, pMsgInfo->buffer, pMsgInfo->header.dataSize);
    len = bmser_calculate_crc((uint8_t *)pBuffer, \
            pMsgInfo->header.regNum * 2 + sizeof(struct MQTT_MSG_S));

    return len;
}

static void MqttConnectCallback(struct mosquitto* mosq, void* userdata, int result)
{
    int ret = 0;

    if (MOSQ_ERR_SUCCESS == result)
    {
        ret |= mosquitto_subscribe(mosq, \
                                NULL,   \
                                g_mqtt_mgr.setTopic,  \
                                MQTT_QOS_LEVEL);
        ret |= mosquitto_subscribe(mosq, \
                                NULL,   \
                                g_mqtt_mgr.respTopic,  \
                                MQTT_QOS_LEVEL);
        if (ret != MOSQ_ERR_SUCCESS)
        {
            BMS_MyLogError("mosquitto_subscribe failed, result = %d\n", result);

            return;
        }

        BMS_MyLogInfo("mosquitto_subscribe success");
    }
    else
    {
        BMS_MyLogError("mosquitto_connect failed, result = %d\n", result);
    }
}

static void MqttMessageCallback(struct mosquitto* mosq, void* userdata, \
                                const struct mosquitto_message* message)
{
    int ret = 0;
    struct BMSER_MSG_RING_INFO msgInfo = {0};

    if (strstr(message->topic, RESP_TOPIC_KEY_NAME) == NULL)
    {
        BMS_MyLogDebug("topic is not setresp topic, topic = %s\n", message->topic);

        return;
    }

    memset(&msgInfo, 0, sizeof(struct BMSER_MSG_RING_INFO));

    if (message->payloadlen > 0)
    {
        ret = DecodeMqttMsg(&msgInfo, message->payload, message->payloadlen);
        if (ret != 0)
        {
            BMS_MyLogError("DecodeMqttMsg failed, ret = %d\n", ret);

            return;
        }

        BMS_MyLogDebug("func = %d, slaveID = %d, startAddr = %d, regNum = %d, dataSize = %d\n", \
                        msgInfo.header.func, msgInfo.header.slaveID, msgInfo.header.startAddr, \
                        msgInfo.header.regNum, msgInfo.header.dataSize);
    }
}

int BMS_ModbusTcpPoll_StartMqttMsgProc(void)
{
    int ret = 0;

    ret = bmser_dev_get_board_sn(g_mqtt_mgr.gwSn);
    if (ret != 0)
    {
        BMS_MyLogError("bmser_dev_get_board_sn failed, ret = %d\n", ret);

        return ret;
    }

    ret = BMS_GetDevSN(g_mqtt_mgr.gwSn, g_mqtt_mgr.devSn);
    if (ret != 0)
    {
        BMS_MyLogError("BMS_GetDevSN failed, ret = %d\n", ret);

        return ret;
    }

    snprintf(g_mqtt_mgr.setTopic,   \
            MQTT_TOPIC_MAX_LEN, \
            MODBUS_TCP_POLL_MQTT_SET_TOPIC_FMT, \
            g_mqtt_mgr.gwSn,    \
            g_mqtt_mgr.devSn);

    snprintf(g_mqtt_mgr.respTopic,  \
            MQTT_TOPIC_MAX_LEN, \
            MODBUS_TCP_POLL_MQTT_RESP_TOPIC_FMT,    \
            g_mqtt_mgr.gwSn,    \
            g_mqtt_mgr.devSn);

    BMS_MyLogInfo("setTopic = %s", g_mqtt_mgr.setTopic);
    BMS_MyLogInfo("respTopic = %s", g_mqtt_mgr.respTopic);

    ret = mosquitto_lib_init();
    if (ret != MOSQ_ERR_SUCCESS)
    {
        goto ERR_EXIT;
    }

    g_mosq = mosquitto_new("modbus_tcp_poll_mqtt_test", true, NULL);
    if (g_mosq == NULL)
    {
        goto ERR_EXIT;
    }

    mosquitto_connect_callback_set(g_mosq, MqttConnectCallback);
    mosquitto_message_callback_set(g_mosq, MqttMessageCallback);

    ret = mosquitto_connect(g_mosq,   \
                            LOCAL_MQTT_IP,    \
                            MQTT_CONNECT_PORT,  \
                            MQTT_KEEP_ALIVE);
    if (ret != MOSQ_ERR_SUCCESS)
    {
        goto ERR_EXIT;
    }

    ret = mosquitto_loop_start(g_mosq);
    if (ret != MOSQ_ERR_SUCCESS)
    {
        goto ERR_EXIT;
    }

    BMS_MyLogInfo("mosquitto_loop_start success");

    return 0;

ERR_EXIT:
    if (g_mosq != NULL)
    {
        mosquitto_destroy(g_mosq);
    }

    mosquitto_lib_cleanup();

    return -1;
}

int main(int argc, char const *argv[])
{
    int i = 0;
    int ret = 0;
    uint8_t buffer[1024] = {0};
    struct BMSER_MSG_RING_INFO msgInfo = {0};

    ret = BMS_ModbusTcpPoll_StartMqttMsgProc();
    if (ret != 0)
    {
        BMS_MyLogError("BMS_ModbusTcpPoll_StartMqttMsgProc failed, ret = %d\n", ret);

        return ret;
    }

    msgInfo.header.func = WRITE;
    msgInfo.header.slaveID = 1;
    msgInfo.header.startAddr = 0x0000;
    msgInfo.header.regNum = 0x20;
    msgInfo.header.dataSize = 0x20 * 2;
    for (i = 0; i < 0x20; i++)
    {
        ((uint16_t *)msgInfo.buffer)[i] = i;
    }

    ret = EncodeMqttMsg(&msgInfo, buffer);
    if (ret < 0)
    {
        BMS_MyLogError("EncodeMqttMsg failed, ret = %d\n", ret);

        return ret;
    }
    
    ret = mosquitto_publish(g_mosq, NULL, g_mqtt_mgr.setTopic,  \
                            ret, buffer, MQTT_QOS_LEVEL, false);
    if (ret != 0)
    {
        BMS_MyLogError("publish failed");

        return ret;
    }

    while (1)
    {
        sleep(10);
    }
    

    BMS_MyLogDebug("publish success");

    return 0;
}

