/*
 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
 */

#include <stdio.h>
#include <string.h>
#include "iot_export.h"
#include "iot_import.h"
#include "iot_infra.h"
#include "iotx_utils.h"
#include "iotx_system.h"
#include "iotx_log.h"
#include "awss_reset.h"
#include "awss_reset_statis.h"

#if defined(__cplusplus)  /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif

#define AWSS_RESET_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "dev_reset")
#define AWSS_RESET_FREE(ptr)    LITE_free(ptr)

static uint8_t awss_report_reset_suc = 0;
static uint16_t awss_report_reset_id = 0;
static void *report_reset_timer = NULL;

int awss_report_reset_to_cloud();

void awss_report_reset_reply(void *pcontext, void *pclient, void *mesg)
{
    char rst = 0;

    iotx_mqtt_event_msg_pt msg = (iotx_mqtt_event_msg_pt)mesg;

    switch (msg->event_type) {
        case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
            break;
        default:
            return;
    }

    log_debug("[RST]", "%s\r\n", __func__);

    awss_report_reset_suc = 1;
    HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0);

    HAL_Timer_Stop(report_reset_timer);
    HAL_Timer_Delete(report_reset_timer);
    report_reset_timer = NULL;

    AWSS_RST_UPDATE_STATIS(AWSS_RST_STATIS_SUC);

    iotx_event_post(IOTX_RESET);  // for old version of event
    do {  // for new version of event
        void *cb = NULL;
        cb = (void *)iotx_event_callback(ITE_AWSS_STATUS);
        if (cb == NULL) break;
        ((int (*)(int))cb)(IOTX_RESET);
    } while (0);

    AWSS_RST_DISP_STATIS();

#ifdef DEV_BIND_ENABLED
    extern int awss_start_bind();
    awss_start_bind();
#endif
}

int awss_report_reset_to_cloud()
{
    int ret;
    int final_len = 0;
    char *topic = NULL;
    char *packet = NULL;
    int packet_len = AWSS_RESET_PKT_LEN;
    int topic_len = AWSS_RESET_TOPIC_LEN;

    if (awss_report_reset_suc) {
        dump_dev_bind_status(STATE_BIND_ALREADY_RESET, NULL);
        return STATE_BIND_ALREADY_RESET;
    }

    AWSS_RST_UPDATE_STATIS(AWSS_RST_STATIS_START);

    if (report_reset_timer == NULL) {
        report_reset_timer = HAL_Timer_Create("report_rst", (void (*)(void *))awss_report_reset_to_cloud, NULL);
    }
    HAL_Timer_Stop(report_reset_timer);
    HAL_Timer_Start(report_reset_timer, 3000);

    do {
        char pk[PRODUCT_KEY_LEN + 1] = {0};
        char dn[DEVICE_NAME_LEN + 1] = {0};

        HAL_GetProductKey(pk);
        HAL_GetDeviceName(dn);

        topic = (char *)AWSS_RESET_MALLOC(topic_len + 1);
        if (topic == NULL) {
            ret = STATE_SYS_DEPEND_MALLOC;
            dump_dev_bind_status(STATE_BIND_REPORT_RESET_FAIL, "topic malloc fail");
            goto REPORT_RST_ERR;
        }
        memset(topic, 0, topic_len + 1);

        HAL_Snprintf(topic, topic_len, TOPIC_RESET_REPORT_REPLY, pk, dn);

#ifdef MQTT_AUTO_SUBSCRIBE
        ret = IOT_MQTT_Subscribe(NULL, topic, IOTX_MQTT_QOS3_SUB_LOCAL,
                                 (iotx_mqtt_event_handle_func_fpt)awss_report_reset_reply, NULL);
#else
        ret = IOT_MQTT_Subscribe(NULL, topic, IOTX_MQTT_QOS0,
                                 (iotx_mqtt_event_handle_func_fpt)awss_report_reset_reply, NULL);
#endif
        if (ret < 0) {
            dump_dev_bind_status(STATE_BIND_REPORT_RESET_FAIL, "awss reset reply sub fail");
            goto REPORT_RST_ERR;
        }

        memset(topic, 0, topic_len + 1);
        HAL_Snprintf(topic, topic_len, TOPIC_RESET_REPORT, pk, dn);
    } while (0);

    packet = AWSS_RESET_MALLOC(packet_len + 1);
    if (packet == NULL) {
        ret = STATE_SYS_DEPEND_MALLOC;
        dump_dev_bind_status(STATE_BIND_REPORT_RESET_FAIL, "awss reset malloc fail");
        goto REPORT_RST_ERR;
    }
    memset(packet, 0, packet_len + 1);

    do {
        char id_str[AWSS_RESET_MSG_ID_LEN + 1] = {0};
        HAL_Snprintf(id_str, AWSS_RESET_MSG_ID_LEN, "\"%u\"", awss_report_reset_id ++);
        final_len = HAL_Snprintf(packet, packet_len, AWSS_RESET_REQ_FMT, id_str, METHOD_RESET_REPORT, "{}");
    } while (0);

    log_debug("[RST]", "report reset:%s\r\n", packet);

    ret = IOT_MQTT_Publish_Simple(NULL, topic, IOTX_MQTT_QOS0, packet, final_len);
    log_debug("[RST]", "report reset result:%d\r\n", ret);
    if (ret < 0) {
        dump_dev_bind_status(STATE_BIND_REPORT_RESET_FAIL, topic);
    }
REPORT_RST_ERR:
    if (packet) AWSS_RESET_FREE(packet);
    if (topic) AWSS_RESET_FREE(topic);
    return ret;
}

int awss_report_reset()
{
    char rst = 0x01;
    int ret;
    awss_report_reset_suc = 0;

    /* guocheng.kgc add for filter unbind msg when device reset */
    HAL_Kv_Set(AWSS_KV_RST_FLAG, &rst, sizeof(rst), 0);
    ret = HAL_Kv_Set(AWSS_KV_RST, &rst, sizeof(rst), 0);
    if (ret < 0) {
        dump_dev_bind_status(STATE_SYS_DEPEND_KV_SET, AWSS_KV_RST);
    }
    return awss_report_reset_to_cloud();
}

int awss_check_reset()
{
    int len = 1;
    char rst = 0;

    int ret = HAL_Kv_Get(AWSS_KV_RST, &rst, &len);
    if (rst != 0x01) { // reset flag is not set
        log_debug("[RST]", "no rst\r\n");
        return 0;
    }
    log_debug("[RST]", "need report rst\r\n");
    awss_report_reset_suc = 0;

    (void)ret;
    return 1;
}

int awss_stop_report_reset()
{
    if (report_reset_timer == NULL) {
        dump_dev_bind_status(STATE_BIND_ALREADY_RESET, AWSS_KV_RST);
        return STATE_BIND_ALREADY_RESET;
    }

    HAL_Timer_Stop(report_reset_timer);
    HAL_Timer_Delete(report_reset_timer);
    report_reset_timer = NULL;

    return 0;
}

#if defined(__cplusplus)  /* If this is a C++ compiler, use C linkage */
}
#endif
