#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include "mqtt_session.h"
#include "dy_utils/dy_common.h"
#include "cloud_conn_common.h"
#include "dy_utils/cJSON.h"
#include "dy_utils/protocol.h"


#define VENDOR "dayun"
#define PUBLISH_TOPIC "G/"VENDOR"/Evt_RealData"
#define PREFIX "/app/config/zhaoming"
#define GENERIC_CONFIG PREFIX"/generic.json"
#define LIMIT_CONFIG PREFIX"/limit.json"
#define MQTT_ZHAOMING PREFIX"/mqtt.json"
extern host_cmd_t g_host_cmd[];

int set_period_hook(cloud_conn_var_t *var,cJSON *root,char **out);
int set_thr_hook(cloud_conn_var_t *var,cJSON *root,char **out);
int get_thr_hook(cloud_conn_var_t *var,cJSON *root,char **out);

struct recv_hook_t
{
    int msgid;
    int (* hook)(cloud_conn_var_t *var,cJSON *root,char **out);
}recv_hook_t;

struct recv_hook_t recv_hooks[] =
{
{8001,set_period_hook},
{8011,set_period_hook},
{8003,set_thr_hook},
{8005,get_thr_hook},
};


static int cloud_conn_subscribe_all(cloud_conn_var_t *var)
{
    mqtt_session_t *mqtt_session = var->session_cloud;
    char topic[64];

    sprintf(topic, "S/+/%s", var->sn_str);
    mqtt_session_subscribe(mqtt_session, topic);

    return 0;
}

static int cloud_conn_state_change(void *obj, int state)
{
    cloud_conn_var_t *var = (cloud_conn_var_t *)obj;

    switch (state)
    {
        case MQTT_CONNECTING:
            var->comm_status = COMM_STATUS_CONNECTING;
            break;
        case MQTT_CONNECTED:
            var->comm_status = COMM_STATUS_CONNECTED;
            if (!var->status_timer)
            {
                //开启心跳超时检查定时器
                var->status_timer = my_timer_create();
                if (var->status_timer <= 0)
                {
                    dy_syslog(LOG_INFO, "[ERR] create status check timer fail, %d", var->status_timer);
                }

                if (var->status_timer > 0)
                {
                    my_timer_set(var->status_timer, 2, 2000);
                }
            }
            break;
        case MQTT_DISCONNECTED:
            var->comm_status = COMM_STATUS_IDLE;
            break;
        default:
            dy_syslog(LOG_ERR, "wrong mqtt state:%d", state);
    }

}

static char *heartbeat_print(cloud_conn_var_t *var)
{
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        return NULL;
    }
    char *str = (cJSON_Print(root));
    cJSON_Delete(root);
    return str;
}

static char *packet_encode(cloud_conn_var_t *var,int msgig,char *data)
{
    if(!data) return NULL;
    cJSON *root_data = cJSON_Parse(data);
    cJSON_AddStringToObject(root_data, "fsuid", var->sn_str);
    cJSON_AddStringToObject(root_data, "suNmae", var->sta_name_str);
    free(data);
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        return NULL;
    }
    cJSON_AddNumberToObject(root, "msgid", msgig);
    time_t t = time(NULL) + 8*3600;
    char buff[50]={0};
    struct tm tm;
    localtime_r(&t,&tm);
    size_t  size = strftime(buff,sizeof(buff),"%Y-%m-%d %X",&tm);
    if (size <= 0 )return NULL;
    cJSON_AddStringToObject(root, "time", buff);
    cJSON_AddItemToObject(root, "data", root_data);
    char *str = (cJSON_Print(root));
    cJSON_Delete(root);
    return str;
}

void timer_heart_beat(cloud_conn_var_t *var)
{
    char *str = NULL;
    str = packet_encode(var,1,heartbeat_print(var));
    mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
    free(str);
}

void report_picture_signal(cloud_conn_var_t *var,char *path)
{
    char *str = NULL;
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)return;
    cJSON_AddStringToObject(root, "pic_path", path);
    char *json_str = (cJSON_Print(root));
    str = packet_encode(var,301,json_str);
    cJSON_Delete(root);
    mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
    free(str);
}

int set_period_hook(cloud_conn_var_t *var,cJSON *recv,char **out)
{
    cJSON *hbtime = cJSON_GetObjectItem(recv,"hbtime");
    if(hbtime)  var->hb_preiod = hbtime->valueint;

    cJSON *pushtime = cJSON_GetObjectItem(recv,"pushtime");
    if(pushtime)  var->rd_preiod = pushtime->valueint;

    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        return -1;
    }
    cJSON_AddNumberToObject(root, "hbtime", var->hb_preiod);
    cJSON_AddNumberToObject(root, "pushtime", var->rd_preiod);
    char *str = (cJSON_Print(root));
    cJSON_Delete(root);
    int size = write_file_data(GENERIC_CONFIG, str, strlen(str));
    free(str);
    return 0;
}

int set_thr_hook(cloud_conn_var_t *var,cJSON *recv,char **out)
{
    char *str = cJSON_Print(recv);
    if(str)
    {
        effect_limit_config(NULL,str);
        int size = write_file_data(LIMIT_CONFIG, str, strlen(str));
        cJSON *root = cJSON_CreateObject();
        cJSON_AddNumberToObject(root,"result",1);
        *out = cJSON_Print(root);
        cJSON_Delete(root);
        free(str);
        return 8004;
    }
    return 0;
}

int get_thr_hook(cloud_conn_var_t *var,cJSON *recv,char **out)
{
    char *str = read_file_data(LIMIT_CONFIG);
    if(str)
    {
        cJSON *root = cJSON_Parse(str);
        cJSON_AddNumberToObject(root,"result",1);
        str = cJSON_Print(root);
        cJSON_Delete(root);
        *out = str;
        return 8006;
    }
    else return 0;
}

int recv_host_msg(void *obj, mqtt_message_t *mqtt_msg)
{
    cloud_conn_var_t *var = (cloud_conn_var_t *)obj;
    dy_syslog(LOG_DEBUG, "MQTT client received MQTT topic:%s payload:%s",
              mqtt_msg->topic, mqtt_msg->payload);

    if(mqtt_msg->payload == NULL)return -1;
    cJSON *root = cJSON_Parse(mqtt_msg->payload);
    cJSON *root_data = cJSON_GetObjectItem(root,"data");
    cJSON *msgid = cJSON_GetObjectItem(root,"msgid");
    char *response = NULL;
    int resp_msgid = 0;
    if (msgid && msgid->valueint > 0)
    {
        int i;
        for(i = 0;i<ARRAY_SIZE(recv_hooks);i++)
        {
            struct recv_hook_t * recv_hook= &recv_hooks[i];
            if (recv_hook->msgid == msgid->valueint)
            {
                resp_msgid = recv_hook->hook(var,root_data,&response);
                break;
            }
        }
        if(i == ARRAY_SIZE(recv_hooks))
        {
           dy_syslog(LOG_ERR, "msgid [%d] swas invaild", msgid->valueint);
        }

    }
    cJSON_Delete(root);

    if(resp_msgid > 0)
    {
        char *str = NULL;
        str = packet_encode(var,resp_msgid,response);
        mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
        free(str);
    }
    return 0;
}



int comm_status_poll(cloud_conn_var_t *var)
{
    TIMER_CONFIRM(var->status_timer);

    char *response = get_sensor_alarm(var);
    if(response)
    {
        char *str = NULL;
        str = packet_encode(var,201,response);
        mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
        free(str);
    }

    time_t t =  time(NULL);
    static time_t heartbeat_time = 0;
    if(difftime(t,heartbeat_time) >= var->hb_preiod)
    {
        heartbeat_time = t;
        timer_heart_beat(var);
    }
    static time_t last = 0;
    if(difftime(t,last) >= var->rd_preiod)
    {
        last = t;
        char *response = get_sensor_value(var);
        char *str = NULL;
        str = packet_encode(var,101,response);
        mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
        free(str);

        #ifdef EN_3RD_RTU
            response = get_3rd_rtu_value(var);
            if(response)
            {
                str = packet_encode(var,401,response);
                mqtt_session_publish(var->session_cloud, PUBLISH_TOPIC, str, strlen(str));
                free(str);
            }
        #endif
    }
    pthread_mutex_lock(&var->mx_path);
    list_pic_path *tmp = NULL;
    list_for_each_entry(tmp,&var->l_path,list)
    {
        if(tmp && tmp->path)//in sending
        {
            dy_syslog(LOG_INFO, "send picture signal, path %s",tmp->path);
            report_picture_signal(var,tmp->path);
        }
        free(tmp->path);
        list_del(&tmp->list);
        free(tmp);
        break;
    }
    pthread_mutex_unlock(&var->mx_path);
    return 0;
}

void effect_generic_config(cloud_conn_var_t *var,char *str)
{
    cJSON *root = cJSON_Parse(str);
    cJSON *hbtime = cJSON_GetObjectItem(root,"hbtime");
    if(hbtime && hbtime->valueint)
    {
        var->hb_preiod = hbtime->valueint;
    }
    cJSON *pushtime = cJSON_GetObjectItem(root,"pushtime");
    if(pushtime && pushtime->valueint)
    {
        var->rd_preiod = pushtime->valueint;
    }
    cJSON_Delete(root);
}


int load_config(cloud_conn_var_t *var)
{
    char *json_str = NULL;
    char *path = PREFIX;
    if(access(path,F_OK) != 0) {
        if(mkdir(path,S_IRWXU) != 0){}
//            printf("creator dir /"%s/" err, errno %d/n",path, errno);
    }

    json_str = read_file_data(GENERIC_CONFIG);
    if (json_str == NULL)
    {
        dy_syslog(LOG_ERR, "load generic config,file %s not exist", GENERIC_CONFIG);
    }
    effect_generic_config(var,json_str);

    json_str = read_file_data(LIMIT_CONFIG);
    if (json_str == NULL)
    {
        dy_syslog(LOG_ERR, "load alarm config,file %s not exist", LIMIT_CONFIG);
    }
    effect_limit_config(var,json_str);

    if (load_server_config(var->session_cloud, MQTT_ZHAOMING) != 0)
    {
        dy_syslog(LOG_ERR, "load mqtt config,file %s failed", MQTT_ZHAOMING);
    }

    return 0;
}


// 建立与broker之间的MQTT连接
int cloud_conn_mqtt_init(cloud_conn_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "%szhaoming", var->sn_str);
    var->session_cloud = mqtt_session_new(clientId, (void*)var);
    if (var->session_cloud == NULL) return -1;

    load_config(var);

    mqtt_session_set_opts(var->session_cloud, DEFAULT_QOS, KEEPALIVEINTERVAL);
    mqtt_session_set_callbacks(var->session_cloud, recv_host_msg, cloud_conn_state_change);
    cloud_conn_subscribe_all(var);
    var->comm_status = COMM_STATUS_CONNECTING;
    mqtt_session_start(var->session_cloud);
}
