#ifndef _vda_5050_CLIENT_H_INCLUDED_
#define _vda_5050_CLIENT_H_INCLUDED_
#include <ros/ros.h>
#include <mosquitto.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include <thread>
#include <amr_comunication/vda_5050/utils/common.h>
#include "amr_comunication/vda_5050/utils/curve_common.h"
#include "amr_comunication/vda_5050/utils/pose.h"


namespace amr_comunication
{
  class VDA5050Connector
  {
  public:
    struct UserParams;

    VDA5050Connector();
    virtual ~VDA5050Connector();
    
    static std::unique_ptr<UserParams> userParams_;
    static vda_5050::Order vda5050_order_;
    static vda_5050::InstantAction vda5050_instant_action_;
    static vda_5050::State vda5050_state_;
    static vda_5050::Visualization vda5050_visualization_;
    static std::mutex state_mutex; // Tạo mutex để bảo vệ vda5050_state_
    static std::mutex visualization_mutex;// Tạo mutex để bảo vệ vda5050_visualization_
    std::map<std::string ,std::shared_ptr<vda_5050::Action>> parallel_execution_list_;

    /**
     * @brief execute an Order
     */
    static std::function<void()> execute_order_;

    /**
     * @brief execute an instant action
     */
    static std::function<void()> execute_instant_action_;

    /**
     * @brief execute an parallel action
     */
    static std::function<void()> execute_parallel_action_;

    /**
     * @brief execute an velocity max action
     */
    static std::function<void(double)> velocity_max_action_;

    /**
     * @brief execute an angular max action
     */
    static std::function<void(double)> angular_max_action_;

  private:

    void mqtt_init();

    void mqtt_cleanup();

    void mqtt_connect();

    void mqtt_reconnect(const std::string& new_host, int new_port);

    std::string getCurrentTimestamp();

    static void mqtt_on_connect_callback(struct mosquitto* mosq, void* userdata, int result);

    static void mqtt_on_disconnect_callback(struct mosquitto* mosq, void* userdata, int rc);

    static void mqtt_message_callback(struct mosquitto* mosq, void* userdata, const struct mosquitto_message* message);
    
    void publishMqttTask();

    void updatingProgress();

    void stateInProgress();

    void orderMsgStream(vda_5050::Order order);

    bool ParseOrderMsg(const std::string &payload, vda_5050::Order &order);

    bool ParseInstantActionMsg(const std::string& payload, vda_5050::InstantAction &instantAction);

    nlohmann::json vda5050VisualizationToJson(const vda_5050::Visualization& visualization);

    nlohmann::json vda5050StateToJson(const vda_5050::State& state);

    template <typename T> bool checkObjectStructure(nlohmann::json json, std::string obj);

    static bool acceptingOrderOrOrderUpdate(const vda_5050::Order &received_order, vda_5050::Order &current_order);

    static bool acceptingInstantActions(const vda_5050::InstantAction &received_instantAction, vda_5050::InstantAction &current_instantAction);

    static bool isTheVehicleStillExecuting(); 

    static bool isTheVehicleWaitingAnUpdate();

    static bool isAGVOnNodeOrInDeviationRange();
    
    static bool isAGVOnNodeOrInDeviationRangeOfNewOrder(vda_5050::Order new_order);

    static void populateNodeStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void appendNodeStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void populateEdgeStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void appendEdgeStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void populateActionStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void appendActionStates(const vda_5050::Order &receiverd_order, vda_5050::State &curent_state);

    static void actionsHandle();
    // properties
    struct mosquitto* mosq_{ nullptr };
    std::thread publish_mqtt_thread_;

  public:

    // global variables
    struct UserParams
    {
      UserParams() {
        mqtt_hostname_ = "0.0.0.0";
        mqtt_port_ = 1883;
        mqtt_keepalive_ = 60;
      }
      void print_params()
      {
        std::cout << "[amr_control_node][Param] mqtt_hostname_: " << mqtt_hostname_ << std::endl;
        std::cout << "[amr_control_node][Param] mqtt_port_: " << mqtt_port_ << std::endl;
        std::cout << "[amr_control_node][Param] mqtt_keepalive_: " << mqtt_keepalive_ << std::endl;
      }
      std::string name_;
      std::string mqtt_hostname_;
      std::string mqtt_client_id_;
      std::string user_name_;
      std::string password_;
      int mqtt_port_;
      int mqtt_keepalive_;
    };
  };
} // namespace amr_comunication


#endif // _vda_5050_CLIENT_H_INCLUDED_