/*
 * Copyright (C) 2020-2020 ikonke
 */



#include "kk_dm_api.h"
#include "kk_tsl_common.h"
#include "kk_dm_mng.h"
#include "com_api.h"
#include "dm_ota.h"
#include "kk_log.h"
#include "kk_hal.h"
#include "kk_dm_queue.h"

static dm_api_ctx_t g_dm_api_ctx;

static dm_api_ctx_t *_dm_api_get_ctx(void)
{
	return &g_dm_api_ctx;
}

static void _dm_api_lock(void)
{
	dm_api_ctx_t *ctx = _dm_api_get_ctx();
	if (ctx->mutex) {
		HAL_MutexLock(ctx->mutex);
	}
}

static void _dm_api_unlock(void)
{
	dm_api_ctx_t *ctx = _dm_api_get_ctx();
	if (ctx->mutex) {
		HAL_MutexUnlock(ctx->mutex);
	}
}

int kk_dm_subdev_register(_IN_ int devid)
{
    int res = 0;
    //dm_mgr_dev_node_t *search_node = NULL;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    _dm_api_lock();
    //res = dm_mgr_search_dev_by_devid(devid, (void **)&search_node);
    //if (res != SUCCESS_RETURN) {
       // _dm_api_unlock();
       //return FAIL_RETURN;
    //}

    res = dm_mgr_upstream_thing_sub_register(devid);

    _dm_api_unlock();
    return res;
}

int kk_dm_subdev_unregister(_IN_ int devid)
{
	int res = 0;

	if (devid < 0) {
		return INVALID_PARAMETER;
	}

	_dm_api_lock();

	res = dm_mgr_upstream_thing_sub_unregister(devid);

	_dm_api_unlock();
	return res;
}

int kk_dm_subdev_topo_add(_IN_ int devid)
{
    int res = 0;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    _dm_api_lock();

    res = dm_mgr_upstream_thing_topo_add(devid);

    _dm_api_unlock();
    return res;
}

int iotx_dm_subdev_topo_del(_IN_ int devid)
{
    int res = 0;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    _dm_api_lock();

    res = dm_mgr_upstream_thing_topo_delete(devid);

    _dm_api_unlock();
    return res;
}
int iotx_dm_ccu_cloud_check(void)
{
	int res = 0;

	_dm_api_lock();
	res = dm_mgr_ccu_status_cloud(0);
	_dm_api_unlock();
	return res;
}

int iotx_dm_dev_online(_IN_ int devid)
{
	int res = 0;
	if (devid < 0) {
		return INVALID_PARAMETER;
	}
	_dm_api_lock();

	res = dm_mgr_upstream_status_online(devid);

	_dm_api_unlock();
	return res;
}

int iotx_dm_dev_offline(_IN_ int devid)
{
	int res = 0;

	if (devid < 0) {
		return INVALID_PARAMETER;
	}

	_dm_api_lock();

	res = dm_mgr_upstream_status_offline(devid);

	_dm_api_unlock();
	return res;
}

int iotx_dm_subdev_login(_IN_ int devid)
{
    int res = 0;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    _dm_api_lock();

    res = dm_mgr_upstream_combine_login(devid);

    _dm_api_unlock();
    return res;
}

int iotx_dm_subdev_logout(_IN_ int devid)
{
    int res = 0;

    if (devid < 0) {
        return INVALID_PARAMETER;
    }

    _dm_api_lock();

    res = dm_mgr_upstream_combine_logout(devid);

    _dm_api_unlock();
    return res;
}


void iotx_dm_dispatch(void)
{
	int count = 0;
	void *data = NULL;
	dm_api_ctx_t *ctx = _dm_api_get_ctx();

#if defined(OTA_ENABLED) && !defined(BUILD_AOS)
	dm_cota_status_check();
	dm_fota_status_check();
#endif
	while (CONFIG_DISPATCH_QUEUE_MAXLEN == 0 || count++ < CONFIG_DISPATCH_QUEUE_MAXLEN) {
		//printf("iotx_dm_dispatch time=%d \n", HAL_UptimeMs());
		if (dm_queue_msg_next(&data) == SUCCESS_RETURN) {
			//dm_queue_msg_t *msg = (dm_queue_msg_t *)data;
			INFO_PRINT("dm_queue_msg_next call \n");
			if (ctx->event_callback) {
				ctx->event_callback(1, data);
			}
			free(data);
			data = NULL;
		}else if(kk_get_cloudstatus()&&dm_queue_msg_next4(&data) == SUCCESS_RETURN){
			kk_ipc_send(IPC_MID2APP, data, strlen(data)+1);
			free(data);
			data = NULL;
		}
		else {
			break;
		}
	}
}

int iotx_dm_connect(_IN_ iotx_dm_event_callback cb)
{
	//int res = 0;
	dm_api_ctx_t *ctx = _dm_api_get_ctx();

	if (cb == NULL) {
		return INVALID_PARAMETER;
	}

	/* DM Event Callback */

	ctx->event_callback = cb;


    /*res = dm_client_connect(IOTX_DM_CLIENT_CONNECT_TIMEOUT_MS);
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }

#ifdef ALCS_ENABLED

    res = dm_server_connect();
    if (res != SUCCESS_RETURN) {
        return FAIL_RETURN;
    }
#endif*/

	return SUCCESS_RETURN;
}

int iotx_dm_open(void)
{
	int res = 0;
	dm_api_ctx_t *ctx = _dm_api_get_ctx();

	memset(ctx, 0, sizeof(dm_api_ctx_t));

	/* DM Mutex Create*/
	ctx->mutex = HAL_MutexCreate();
	if (ctx->mutex == NULL) {
		return MEMORY_NOT_ENOUGH;
	}


	/* DM OTA Module Init */
	res = dm_ota_init();
	if (res != SUCCESS_RETURN) {
		goto ERROR;
	}


	/* DM Cloud Message Parse And Assemble Module Init */
	//res = dm_msg_init();
	//if (res != SUCCESS_RETURN) {
	//    goto ERROR;
	//}


	/* DM QUEUE Module Init */
	res = dm_queue_init(CONFIG_DISPATCH_QUEUE_MAXLEN);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}

	/* DM Manager Module Init */
	res = dm_mgr_init();
	if (res != SUCCESS_RETURN) {
		goto ERROR;
	}


	/* DM OTA Module Init */
	res = dm_ota_sub();
	if (res == SUCCESS_RETURN) {
		/* DM Config OTA Module Init */
		//dm_cota_init();

		/* DM Firmware OTA Mudule Init */
		dm_fota_init();
	}


	return SUCCESS_RETURN;

ERROR:

	dm_mgr_deinit();
	dm_queue_deinit();
	//dm_msg_deinit();


	dm_ota_deinit();


	if (ctx->mutex) {
		HAL_MutexDestroy(ctx->mutex);
	}
	return FAIL_RETURN;
}
int iotx_dm_subscribe_node(dm_mgr_dev_node_t *node)
{
	int res = 0;
	if (node == NULL) {
		return INVALID_PARAMETER;
	}
	//send app to subscribe mqtt
	const char subscribe_cmd[]  =
		"{\"cmd\":\"subscribe\",\"data\":{\"productCode\":\"%s\",\"deviceCode\":\"%s\"}}";
	int len = strlen(subscribe_cmd) +strlen(node->productCode)+ strlen(node->deviceCode) + 1;
	void* buf = malloc(len);

	if (buf){
		HAL_Snprintf(buf, len, subscribe_cmd, node->productCode,node->deviceCode);
		#if 1
		kk_ipc_send(IPC_MID2APP, buf, len);
		free(buf);
		#else
		dm_queue_msg_insert4(buf);
		#endif
	}else{
		ERROR_PRINT("\n [%d][%s] malloc faild kk_ipc_send \n", __LINE__, __FUNCTION__);
		return FAIL_RETURN;
	}
	INFO_PRINT("\n [%d][%s] [%lu] send app to subscribe mqtt  \n", __LINE__, __FUNCTION__, HAL_UptimeMs());
	return SUCCESS_RETURN;
}

int iotx_dm_subscribe(_IN_ int devid)
{
	int res = 0;

	if (devid < 0) {
		return INVALID_PARAMETER;
	}

	dm_mgr_dev_node_t *node = NULL;
	_dm_api_lock();
	res = dm_mgr_search_dev_by_devid(devid, &node);
	if (res != SUCCESS_RETURN) {
		_dm_api_unlock();
		return FAIL_RETURN;
	}
	_dm_api_unlock();

	//send app to subscribe mqtt
	const char subscribe_cmd[]  =
		"{\"cmd\":\"subscribe\",\"data\":{\"productCode\":\"%s\",\"deviceCode\":\"%s\"}}";
	int len = strlen(subscribe_cmd) +strlen(node->productCode)+ strlen(node->deviceCode) + 1;
	void* buf = malloc(len);

	if (buf){
		HAL_Snprintf(buf, len, subscribe_cmd, node->productCode,node->deviceCode);
		#if 0
		kk_ipc_send(IPC_MID2APP, buf, len);
		free(buf);
		#else
		dm_queue_msg_insert4(buf);
		#endif
	}else{
		ERROR_PRINT("\n [%d][%s] malloc faild kk_ipc_send \n", __LINE__, __FUNCTION__);
		return FAIL_RETURN;
	}
	INFO_PRINT("\n [%d][%s] [%lu] send app to subscribe mqtt  \n", __LINE__, __FUNCTION__, HAL_UptimeMs());

	return SUCCESS_RETURN;
}

void kk_dm_ota_report_version(_IN_ int devid, char *version){
    dm_mgr_ota_report_version(devid, version);
}

void kk_dm_ota_send(void *data, int len){
	//dm_queue_msg_insert3(data);
	if (data != NULL){
		void* buf = malloc(len);
		memcpy(buf, data, len);
		printf("------------------------------1\n");
		int res = dm_queue_msg_insert3((void *)buf);
		if (res != SUCCESS_RETURN) {
			free(buf);
			return ;
		}
	}
}

int kk_dm_get_property_type(const char* deviceCode,const char *key)
{
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;
	
	if(deviceCode == NULL){
		return FAIL_RETURN;
	}
	res = dm_mgr_get_device_by_devicecode(deviceCode, &node);
	if (res != SUCCESS_RETURN) {
		return FAIL_RETURN;
	}
	return kk_tsl_get_property_type(node->dev_shadow,key);
}
