#ifndef __MQTT_SESSION_h
#define __MQTT_SESSION_h
#include <pthread.h>
#include <unistd.h>

#include <mosquitto.h>
#include "lnxall_list.h"
#include "ipc_session.h"

#define MAX_HOST_LEN 64
#ifndef MAX_CLIENT_ID_LEN
#define MAX_CLIENT_ID_LEN 150
#endif
#define DEFAULT_QOS 1
#define KEEPALIVEINTERVAL 60

#define MAX_USER_LEN 128
#define MAX_PASS_LEN 128
#define MQTT_CONNECT_INTERVAL 5
#define MAX_PUB_QUEUE_SIZE 600
#define MAX_RX_QUEUE_LENGTH 400
#define PUB_TIMEOUT 5

typedef struct _ipc_msg_s mqtt_message_t;

typedef struct mqtt_client_s
{
    struct mosquitto *mosq;
    char addr[MAX_HOST_LEN];          ///< MQTT地址
    char clientId[128]; ///< clientId
    char user[MAX_USER_LEN];          ///< MQTT地址
    char pass[MAX_PASS_LEN];          ///< MQTT地址
    unsigned short port;              ///<端口
    unsigned char qos;                ///< 0：最多一次的传输 1：至少一次的传输 2： 只有一次的传输
    int keepalive;                    ///
    char *tls_cafile;
    char *tls_certfile;
    char *tls_keyfile;
} mqtt_client_t;

/*
 * MQTT SESSION
 * */
typedef enum _mqtt_state
{
    MQTT_CONNECTING,   // 正在连接
    MQTT_CONNECTED,    // 已连接
    MQTT_DISCONNECTED, //主动断开连接
} mqtt_state_e;

typedef struct _mqtt_session_s
{
    mqtt_client_t client; // MQTT client
    void *user_data;
    mqtt_state_e state;          // MQTT 连接状态
    struct list_head topic_list; // 已经订阅的topic 列表，重连时需要重新订阅
    struct list_head rcv_list;   //收到的消息列表
    int (*handle_recv_msg)(void *obj, mqtt_message_t *mqtt_msg);
    int (*connect_state_change)(void *obj, int state); // 连接状态变化时调用的callback函数
    pthread_mutex_t recv_lock;
    pthread_cond_t recv_cond;
    pthread_rwlock_t topic_lock;
    int received;
    int send_id;
    pthread_mutex_t pub_lock;
    pthread_cond_t pub_cond;
} mqtt_session_t;

typedef struct topic_node_s
{
    struct list_head list;
    int tid;
    char topic[0];
} topic_node_t;

/**
*******************************************************************************
*
* @brief  设置MQTT会话的回调函数
* @param session MQTT 会话结构体的指针
* @param on_message 收到MQTT消息时的回调函数，其中obj为mqtt_session_init时传入的user_data
* @param on_state_change MQTT连接状态发生改变时的回调函数
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_set_callbacks(mqtt_session_t *session, int (*on_message)(void *obj, mqtt_message_t *mqtt_msg),
                                      int (*on_state_change)(void *obj, int state));

/**
*******************************************************************************
*
* @brief  设置MQTT会话的选项
* @param session MQTT 会话结构体的指针
* @param qos 在发布消息时将采用此qos进行发布
* @param keepalive MQTT连接的keepalive时间
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_set_opts(mqtt_session_t *session, int qos, int keepalive);

/**
*******************************************************************************
*
* @brief  设置MQTT会话的broker信息
* @param session MQTT 会话结构体的指针
* @param addr broker 地址
* @param port broker 端口
* @param user broker 连接用户名
* @param pass broker 连接密码
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_set_address(mqtt_session_t *session, char *addr, unsigned short port, char *user, char *pass);

/**
*******************************************************************************
*
* @brief  设置MQTT会话的tls信息
* @param session MQTT 会话结构体的指针
* @param tls_cafile broker cafile
* @param tls_certfile broker certfile
* @param tls_keyfile broker keyfile
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_set_tls(mqtt_session_t *session, char *tls_cafile, char *tls_certfile, char *tls_keyfile);

/**
*******************************************************************************
*
* @brief  新建一个MQTT会话
* @param client_id MQTT client ID
* @return NULL for fail
*
*******************************************************************************
*/
extern mqtt_session_t *mqtt_session_new(char *client_id, void *user_data);

/**
*******************************************************************************
*
* @brief  MQTT会话初始化
* @param session MQTT 会话结构体的指针
* @param user_data 用户数据，将在回调函数里返回
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_start(mqtt_session_t *session);

/**
*******************************************************************************
*
* @brief  订阅topic
* @param session MQTT 会话结构体的指针
* @param topic 要订阅的topic
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_subscribe(mqtt_session_t *session, const char *topic);

/**
*******************************************************************************
*
* @brief  订阅topic
* @param session MQTT 会话结构体的指针
* @param topic 要订阅的topic
* @param qos 要订阅的topic的qos
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_subscribe_qos(mqtt_session_t *session, const char *topic, int qos);

/**
*******************************************************************************
*
* @brief  取消订阅topic
* @param session MQTT 会话结构体的指针
* @param topic 要取消订阅的topic
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_unsubscribe(mqtt_session_t *session, char *topic);

/**
*******************************************************************************
*
* @brief  主动建立MQTT的连接
* @param session MQTT 会话结构体的指针
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_conn(mqtt_session_t *session);

/**
*******************************************************************************
*
* @brief 断开MQTT连接
* @param session MQTT 会话结构体的指针
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_disconn(mqtt_session_t *session);

/**
*******************************************************************************
*
* @brief 发布MQTT消息
* @param session MQTT 会话结构体的指针
* @param topic 消息topic
* @param payload 消息体
* @param payloadlen 消息长度
* @return 0 for success
*
*******************************************************************************
*/
extern int mqtt_session_publish(mqtt_session_t *session, char *topic, const void * payload, int payloadlen);

/**
*******************************************************************************
*
* @brief 发布MQTT消息
* @param session MQTT 会话结构体的指针
* @param topic 消息topic
* @param payload 消息体
* @param payloadlen 消息长度
* @param qos 指定qos
* @return 0 for success
*
*******************************************************************************
*/
extern int mqtt_session_publish_qos(mqtt_session_t *session, char *topic, const void * payload, int payloadlen,int qos);


/**
*******************************************************************************
*
* @brief 阻塞调用publish，当QoS > 0时只有调用到on_publish的回调才返回，，默认超时时间为5秒
* @param session MQTT 会话结构体的指针
* @param topic 消息topic
* @param payload 消息体
* @param payloadlen 消息长度
* @return 0 for success
*
*******************************************************************************
*/
int mqtt_session_publish_sync(mqtt_session_t *session, char *topic, const void *payload, int payloadlen);

/**
*******************************************************************************
*
* @brief 加载MQTT的配置文件
* @param session MQTT 会话结构体的指针
* @param cfg_file 配置文件
*   {
        "host":""
        "port":""
        "user":""
        "pass":""
    }
* @return 0 for success
*
*******************************************************************************
*/
extern int load_server_config(mqtt_session_t *session, char *cfg_file);

/**
*******************************************************************************
*
* @brief  Does a topic match a subscription?
* @param sub[in] 订阅的topic
* @param topic[in] 收到的topic
* @param result[out] 返回是否匹配
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_topic_matches_sub(const char *sub, const char *topic, unsigned char *result);

/**
*******************************************************************************
*
* @brief 自定义QoS和Retain的publish
* @param session MQTT 会话结构体的指针
* @param topic 消息topic
* @param payload 消息体
* @param payloadlen 消息长度
* @param qos  Qos
* @param retain retain
* @return 0 for success
*
*******************************************************************************
*/
extern int mqtt_session_publish_with_flag(mqtt_session_t *session, char *topic, char *payload, int payloadlen, int qos, bool retain);

/**
*******************************************************************************
*
* @brief  获取MQTT状态
* @param session MQTT 会话结构体的指针
* @return
    MQTT_CONNECTING, // 正在连接
    MQTT_CONNECTED, // 已连接
    MQTT_DISCONNECTED, //主动断开连接
*
*******************************************************************************
*/
extern mqtt_state_e mqtt_session_get_state(mqtt_session_t *session);

/**
*******************************************************************************
*
* @brief  获取MQTT会话的client ID
* @param session MQTT 会话结构体的指针
* @return client_id for success; NULL for fail
*
*******************************************************************************
*/
extern char *mqtt_session_get_client_id(mqtt_session_t *session);

/**
*******************************************************************************
*
* @brief 销毁MQTT session
* @param session MQTT 会话结构体的指针
* @return 0 for success; -1 for fail
*
*******************************************************************************
*/
extern int mqtt_session_destroy_and_free(mqtt_session_t *session);
#endif /* __MQTT_CONN_H */
