#include "MQTTClient.h"
#include "rclcpp/rclcpp.hpp"
#include "interface/msg/route.hpp"
#include "json.h"
#include "sub_jingmen_node.hpp"

#include <fstream>
#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sstream>
#include <iomanip>
#include <pthread.h>

Json::Value root;
Json::Reader reader;
std::string routeId = "e6f09885791749d8a26968c21a5d3905";
std::string sub_jingmen_topic;
int time_cunt = 0;
constexpr auto ADDRESS = "tcp://vccs.jmbigdata.cn:1883"; // 荆门
constexpr auto CLIENTID_SUB = "MINIBUS_CLIENT_SUB_JM";   // 更改此处客户端ID

// constexpr auto SUB_jingmen_TOPIC = "/vehicle/{vid}/line/down";
// e6f09885791749d8a26968c21a5d3905 nei
// 8b55528fb27c44f7a1b2d56d5d614ddf wai

const char *getSubTopic()
{
    return sub_jingmen_topic.c_str();
}

constexpr auto QOS = 1;
constexpr auto TIMEOUT = 10000L;

volatile MQTTClient_deliveryToken deliveredtoken;

char sub_buff[500];

void delivered(void *context, MQTTClient_deliveryToken dt)
{
    (void)context;
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    (void)context;
    (void)topicLen;
    time_cunt = 0;
    printf("Message arrived\n");
    printf("topic: %s\n", topicName);
    printf("message: %.*s\n", message->payloadlen, (char *)message->payload);

    memset(sub_buff, 0, sizeof(sub_buff));
    memcpy(&sub_buff, (char *)message->payload, message->payloadlen);

    root.clear();

    if (!reader.parse(sub_buff, root))
    {
        printf("recv json fail\n");
        return 1;
    }
    else
    {
        std::cout << root << std::endl;

        routeId = root["routeId"].asString();
        std::cout << routeId << std::endl;
    }

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    (void)context;
    printf("\nConnection lost\n");
    printf("cause: %s\n", cause);
}

void *mqtt_sub_jingmen(void *arg)
{
    (void)arg;
    MQTTClient client;
    // MQTTClient_deliveryToken token_d_m;

    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    // MQTTClient_message pubmsg_d_m = MQTTClient_message_initializer;
    const char *SUB_jingmen_TOPIC = getSubTopic();

    int rc;
    char *username = NULL;
    char *password = NULL;

    if ((rc = MQTTClient_create(&client, ADDRESS, CLIENTID_SUB, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to create client, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    if ((rc = MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to set callbacks, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    conn_opts.username = username;
    conn_opts.password = password;

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n", SUB_jingmen_TOPIC, CLIENTID_SUB, QOS);
    if ((rc = MQTTClient_subscribe(client, SUB_jingmen_TOPIC, QOS)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to subscribe, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    while (1)
    {
        usleep(200000);
    }

    if ((rc = MQTTClient_unsubscribe(client, SUB_jingmen_TOPIC)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to unsubscribe, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to disconnect, return code %d\n", rc);
        MQTTClient_destroy(&client);
        return NULL;
    }

    MQTTClient_destroy(&client);
    return NULL;
}

class sub_jingmen_node : public rclcpp::Node
{
public:
    // 构造函数,有一个参数为节点名称
    sub_jingmen_node(std::string name) : Node(name)
    {
        RCLCPP_INFO(this->get_logger(), "%s节点已经启动.", name.c_str());
        msg_publisher_ = this->create_publisher<interface::msg::ROUTE>("ROUTE_JINGMEN", 10);
        timer_ = this->create_wall_timer(std::chrono::milliseconds(100), std::bind(&sub_jingmen_node::timer_callback, this));
    }

private:
    void timer_callback()
    {
        time_cunt++;
        interface::msg::ROUTE message;
        message.route_id = routeId;

        msg_publisher_->publish(message);
    }

    // 声名定时器指针
    rclcpp::TimerBase::SharedPtr timer_;
    // 声明话题发布者指针
    rclcpp::Publisher<interface::msg::ROUTE>::SharedPtr msg_publisher_;
};

void init_main()
{
    Json::Reader reader;
    Json::Value root;
    std::ifstream in("config.json", std::ios::binary);
    if (!in.is_open())
    {
        std::cout << "read config file error" << std::endl;
        return;
    }
    if (reader.parse(in, root))
    {
        sub_jingmen_topic = root["mqtt"]["sub_jingmen_topic"].asString();
    }
}

pthread_t mqtt_sub_jingmen_thread_t;

int main(int argc, char **argv)
{
    init_main();
    pthread_create(&mqtt_sub_jingmen_thread_t, NULL, mqtt_sub_jingmen, NULL);

    rclcpp::init(argc, argv);
    /*创建对应节点的共享指针对象*/
    auto node = std::make_shared<sub_jingmen_node>("sub_jingmen_node");
    /* 运行节点，并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();

    return 0;
}