#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "cJSON.h"
#include "com_api.h"
#include "kk_hal.h"
#include "kk_product.h"
#include "kcloud_config.h"
#include "infra_sha256.h"
#include "kk_log.h"
#define BUFSIZE 1024
#define PRODUCTSECRET  "123456"

int kk_execel_cmd(char * cmd,char * buf,int buf_len,int* ret_len)
{
	if(cmd == NULL || buf == NULL || buf_len == 0)
	{
		INFO_PRINT("arg error\n");
		return -1;
	}

	memset(buf,0,buf_len);

	FILE *fp = NULL;
	fp = popen(cmd,"r");
	while(fgets(buf,buf_len,fp)!=NULL){
		INFO_PRINT("%s return %s",cmd,buf);  
	}
	pclose (fp);

	*ret_len = strlen(buf);
	return 0;
}
int kk_parse_deviceSecret(char *info){
	FILE *fp;
	if(info == NULL){
		return -1;
	}
	cJSON* infoObj = cJSON_Parse(info);
	if(infoObj == NULL){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);        
		return -1;
	}
	//cJSON *data = cJSON_GetObjectItem(infoObj,"data");
	//if(data == NULL)
	//{
		//return -1;
	//}
	cJSON *deviceSecret = cJSON_GetObjectItem(infoObj,"deviceSecret");
	if(deviceSecret == NULL) return -1;
	fp = fopen(KK_DEVICESECRET_PATH, "w+");
	if(fp != NULL){
		fwrite(deviceSecret->valuestring,strlen(deviceSecret->valuestring),1,fp);
		fclose(fp);
	}
	return 0;
}
int kk_parse_token(char *info){
	FILE *fp;
	if(info == NULL){
		INFO_PRINT("[%s][%d]\n",__FUNCTION__,__LINE__);
		return -1;
	}
	cJSON* infoObj = cJSON_Parse(info);
	if(infoObj == NULL){
		return -1;
	}
	cJSON *data = cJSON_GetObjectItem(infoObj,"data");
	if(data == NULL)
	{
		return -1;
	}
	cJSON *jwt = cJSON_GetObjectItem(data,"jwt");
	if(jwt == NULL) return -1;
	fp = fopen(KK_TOKEN_PATH, "w+");
	if(fp != NULL){
		fwrite(jwt->valuestring,strlen(jwt->valuestring),1,fp);
		fclose(fp);
		system("sync");
	}
	//cJSON *ccuid = cJSON_GetObjectItem(infoObj,"ccu_id");
	//if(ccuid == NULL) return -1;	
	//fp = fopen("/usr/kk/kk_ccuid.txt", "w+");
    //if(fp != NULL){
        //fwrite(ccuid->valuestring,strlen(ccuid->valuestring),1,fp);
	    //fclose(fp);
   // }
	return 0;
}
char *kk_dictionary_order(char *deviceCode, char *productCode,char *randomId)
{
	char str[3][16]={0};
	char temp[16];
	int i,l,len;
	char *signSource = NULL;  
	memcpy(&str[0],deviceCode,strlen(deviceCode));
	memcpy(&str[1],productCode,strlen(productCode));
	memcpy(&str[2],randomId,strlen(randomId));    
	//for (i=0;i<3;i++)
	//{
		//for (l=0;l<16;l++)
		//{
			//INFO_PRINT("%c",str[i][l]);
		//}
		//INFO_PRINT("\n");
	//}
	//排序
	INFO_PRINT("after order：\n");
	int j,k;
	for( j=0;j<3;j++)
	for( k=j+1;k<3;k++)
	{
		if(strcmp(str[j],str[k])>0)
		{//交换
			strcpy(temp,str[j]);
			strcpy(str[j],str[k]);
			strcpy(str[k],temp);
		}
	}
		//for(i=0;i<3;i++)//输出
			//INFO_PRINT("%s\n",str[i]);
	len = strlen(deviceCode) + strlen(productCode) + strlen(randomId) + 1;            
	signSource = malloc(len);
	if (signSource == NULL) {
		return NULL;
	}
	memset(signSource, 0, len);
	snprintf(signSource, len, "%s%s%s", str[0],str[1],str[2]);  
	INFO_PRINT("signSource %s\n",signSource);
	return signSource;           
}

static const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int base64_encode( const unsigned char *bindata, char *base64, int binlength )
{
    int i, j;
    unsigned char current;

    for ( i = 0, j = 0 ; i < binlength ; i += 3 )
    {
        current = (bindata[i] >> 2) ;
        current &= (unsigned char)0x3F;
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;
        if ( i + 1 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;
        if ( i + 2 >= binlength )
        {
            base64[j++] = base64char[(int)current];
            base64[j++] = '=';
            break;
        }
        current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );
        base64[j++] = base64char[(int)current];

        current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;
        base64[j++] = base64char[(int)current];
    }
    base64[j] = '\0';
    return 0;
}
int arrayToStr(unsigned char *buf, unsigned int buflen, char *out)
{
    char strBuf[65] = {0};
    char pbuf[32];
    int i;
    for(i = 0; i < buflen; i++)
    {
        sprintf(pbuf, "%02x", buf[i]);
        strncat(strBuf, pbuf, 2);
    }
    strncpy(out, strBuf, buflen * 2);
    INFO_PRINT("out = %s\n", out);
    return buflen * 2;
}

static char * kk_create_register_info()
{
	cJSON *root;
	char *out = NULL;
	char *productCode = KK_CCU_PRODUCTID;
	char *signSource,*base64Out = NULL;
	char mac[16] = {0};
	char ramdonId[16] = {0};
	unsigned char sign_hex[32] = {0};
	char sign_hex_str[65] = {0}; 
	uint8_t productSecret[64] = {0};
	char ccuid[32] = {0};
	int productSecret_len = 0;
	char keyTmp[64] = {0};
	root=cJSON_CreateObject();
	HAL_Get_mac(mac);
	HAL_GetTime_s(ramdonId);
	KK_Get_ccuid(ccuid);
	cJSON_AddStringToObject(root, "deviceCode", ccuid);
	cJSON_AddStringToObject(root, "productCode",productCode);
	signSource = kk_dictionary_order(ccuid,productCode,KK_CCU_RANDOM);
	HAL_Execel_cmd(GET_KEY_CMD,(char *)productSecret,sizeof(productSecret),&productSecret_len);
	if(productSecret_len == 0){
		utils_hmac_sha256((const uint8_t *)signSource, strlen(signSource), (const uint8_t *)PRODUCTSECRET, strlen(PRODUCTSECRET), sign_hex);
	}else{
		memcpy(keyTmp,productSecret,productSecret_len-1);
		utils_hmac_sha256((const uint8_t *)signSource, strlen(signSource), (const uint8_t *)keyTmp, strlen((const char*)keyTmp), sign_hex);
	}

	arrayToStr(sign_hex,32,sign_hex_str);

	base64Out = malloc(128);
	if (base64Out == NULL) {
		return NULL;
	}
	INFO_PRINT("[%s][%d]sign_hex:%s\n",__FUNCTION__,__LINE__,sign_hex_str);
	//memset(base64Out, 0, 128);     
	//base64_encode(sign_hex_str,base64Out,strlen(sign_hex_str));  
	INFO_PRINT("[%s][%d]base64Out:%s\n",__FUNCTION__,__LINE__,base64Out);
	cJSON_AddStringToObject(root, "sign",sign_hex_str);
	cJSON_AddStringToObject(root, "random",KK_CCU_RANDOM);
	free(signSource);
	free(base64Out);
	out=cJSON_Print(root);
	//cJSON_Minify(out);
	cJSON_Delete(root);
	INFO_PRINT("--------------------->kk_create_register_info:%s\n",out);
	return out;
}
char g_clientId[64] = {0};
static char * kk_create_get_jwt_info()
{
	cJSON *root;
	FILE *fp;
	char *out = NULL;
	char timestamp[16] = {0};
	char deviceSecret[64] = {0};
	char ccuid[32] = {0};
	HAL_GetTime_s(timestamp);
	KK_Get_ccuid(ccuid);
	sprintf(g_clientId, CLIENTID, ccuid,timestamp);
	root=cJSON_CreateObject();
	cJSON_AddStringToObject(root, "deviceCode", ccuid);
	cJSON_AddStringToObject(root, "productCode",KK_CCU_PRODUCTID);
	cJSON_AddStringToObject(root, "clientId",g_clientId);
	fp = fopen(KK_DEVICESECRET_PATH, "r");
	if(fp != NULL){
		fread(deviceSecret,1,sizeof(deviceSecret),fp);
		fclose(fp);
	}
	cJSON_AddStringToObject(root, "deviceSecret",deviceSecret);

	out=cJSON_Print(root);
	//cJSON_Minify(out);
	cJSON_Delete(root);
	INFO_PRINT("--------------------->kk_create_get_jwt_info:%s\n",out);
	return out;
}
static int kk_send_register_info(int sockfd,const char * path,int type)
{
	char str1[1024], str2[1024],str[16] = {0};
	char tmp[128] = {0};
	int len = 0;
	memset(str2, 0, sizeof(str2));
	if(type == 0){
		strcat(str2, kk_create_register_info());
	}else{
		strcat(str2, kk_create_get_jwt_info());
	}
	len = strlen(str2);
	sprintf(str, "%d", len);

	memset(str1, 0, sizeof(str1));
	memset(tmp, 0, sizeof(tmp));   
	sprintf(tmp, "POST %s HTTP/1.1\n", path);     
	strcat(str1, tmp);
	memset(tmp, 0, sizeof(tmp)); 
	sprintf(tmp, "Host: %s:%d\n",IPSTR, PORT);  
	strcat(str1, tmp);
	strcat(str1, "Content-Type: application/json\n");
	strcat(str1, "Content-Length: ");
	strcat(str1, str);
	strcat(str1, "\n\n");
	//str2的值为post的数据
	strcat(str1, str2);
	strcat(str1, "\r\n\r\n");
	INFO_PRINT("%s\n",str1);   
	return write(sockfd,str1,strlen(str1));
}
int kk_start_ccu_register(void)
{
	int sockfd, ret, i, h;
	struct sockaddr_in servaddr;
	char buf[1024] = {0}, buf2[1024] = {0};
	fd_set   t_set1;
	struct timeval  tv;
	int registerType = 0;
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		INFO_PRINT("---socket error!\n");
		return -1;
	};
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(PORT);
	if (inet_pton(AF_INET, IPSTR, &servaddr.sin_addr) <= 0 ){
		INFO_PRINT("--inet_pton error!\n");
		close(sockfd);
		return -1;
	};

	if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
		INFO_PRINT("connect error!\n");
		close(sockfd);
		return -1;
	}
	INFO_PRINT("connect successful\n");
	ret = kk_send_register_info(sockfd,"/deviceRegister/register",0);
	if (ret < 0) {
		INFO_PRINT("send fail\n");
		close(sockfd);
		return -1;
	}else{
		INFO_PRINT("send success send %d bytes！\n\n", ret);
	}
	registerType = 1;
	FD_ZERO(&t_set1);
	FD_SET(sockfd, &t_set1);
	tv.tv_sec= 1;
	tv.tv_usec= 0;
	h= 0;
	while(1){
		h = select(sockfd +1, &t_set1, NULL, NULL, &tv);
		//if (h == 0) continue;
		if (h == -1) {
			close(sockfd);
			return -1;
		};
		if ( FD_ISSET(sockfd, &t_set1) ){
			memset(buf, 0, 1024);
			memset(buf2, 0, 1024);
			i= read(sockfd, buf, 1024);
			if (i==0){
				close(sockfd);
				return -1;
			}
			INFO_PRINT("\n get %s\n",buf);
			if(registerType == 1){//get deviceSecret
				char* deviceSecret = strstr(buf,"deviceSecret");
				if(deviceSecret != NULL){ 
					char* start = strchr(buf,'{');
					char* end = strrchr(buf,'}');
					strncpy(buf2,start,end-start+1);
					INFO_PRINT("[%s][%d]buf2:%s\n",__FUNCTION__,__LINE__,buf2);
					ret = kk_parse_deviceSecret(buf2);
					if(ret == 0){
						ret = kk_send_register_info(sockfd,"/auth/generateJwt",1);
						if (ret < 0) {
							INFO_PRINT("send fail'\n");
							close(sockfd);
							return -1;
						}else{
							printf("send success send %d bytes！\n\n", ret);
						}
						registerType = 2;
					}
				}
			}else if(registerType == 2){
				char* jwt = strstr(buf,"jwt");
				if(jwt != NULL){
					char* start = strchr(buf,'{');
					char* end = strrchr(buf,'}');
					if(start != NULL && end != NULL){
						strncpy(buf2,start,end-start+1);
						ret = kk_parse_token(buf2);
						if(ret == 0){
							close(sockfd);
							return 0;
						}
					}
				}
			}
		}
	}
	close(sockfd);
	return -1;
}