package com.yihu.jw.base.service.device;

import com.alibaba.fastjson.JSONObject;
import com.yihu.jw.base.config.YsConfig;
import com.yihu.jw.base.dao.device.YsConfigDao;
import com.yihu.jw.entity.care.device.YsConfigDo;
import com.yihu.jw.util.http.HttpClientUtil;
import com.yihu.jw.utils.encode.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.Security;
import java.util.concurrent.TimeUnit;

/**
 * Created by Bing on 2021/9/24.
 */
@Service
public class YsDeviceService {
    private static Logger logger = LoggerFactory.getLogger(YsDeviceService.class);

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private HttpClientUtil httpClientUtil;
    @Autowired
    private YsConfig ysConfig;
    @Autowired
    private YsConfigDao ysConfigDao;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 获取萤石设备assesToken
     */
    public String getAccessToken(String deviceSn) throws Exception {
        YsConfigDo YSCONFIGDO = ysConfig.getConfig(deviceSn);

        if(redisTemplate.hasKey(YSCONFIGDO.getAccessTokenKey())){
            return redisTemplate.opsForValue().get(YSCONFIGDO.getAccessTokenKey());
        }

        JSONObject param = new JSONObject();
        param.put("appKey",YSCONFIGDO.getAppKey());
        param.put("appSecret",YSCONFIGDO.getAppSecret());
        HttpEntity<JSONObject> response = httpClientUtil.assesTokenPostHttp(YsConfig.saasAssesToken,param, HttpMethod.POST);
        JSONObject responseBody = response.getBody();
        String assToken = null;
        if (responseBody.getInteger("code")==200){
            assToken = responseBody.getJSONObject("data").getString("accessToken");
            Long expireTime = responseBody.getJSONObject("data").getLong("expiresIn");//token有效期
            redisTemplate.opsForValue().set(YSCONFIGDO.getAccessTokenKey(),assToken,expireTime, TimeUnit.SECONDS);
//            Long ss= redisTemplate.getExpire(YsConfig.redisKey);
//            System.out.println(expireTime+"---"+ss);


        }else {
            throw new Exception("获取token失败");
        }
        return assToken;
    }

    /**
     * 获取IOT开放平台assesToken
     * @return
     * @throws Exception
     */
    public String getIotAccessToken(String deviceSn) throws Exception {
        YsConfigDo YSCONFIGDO = ysConfig.getConfig(deviceSn);

        if(redisTemplate.hasKey(YSCONFIGDO.getIotAccessTokenKey())){
            return redisTemplate.opsForValue().get(YSCONFIGDO.getIotAccessTokenKey());
        }

        JSONObject param = new JSONObject();
        param.put("accessToken",getAccessToken(deviceSn));
        HttpEntity<JSONObject> response = httpClientUtil.assesTokenPostHttp(YsConfig.iotAssesToken,param, HttpMethod.POST);
        JSONObject responseBody = response.getBody();
        String assToken = null;
        if (responseBody.getInteger("code")==200){
            assToken = responseBody.getJSONObject("data").getString("ezOpenAccessToken");
            Long expireTime = responseBody.getJSONObject("data").getLong("expireTime");//token有效截止日期
            Long nowTime = System.currentTimeMillis();
            expireTime = expireTime-nowTime;

            redisTemplate.opsForValue().set(YSCONFIGDO.getIotAccessTokenKey(),assToken,expireTime, TimeUnit.MILLISECONDS);
            //设备解密密钥
            String secretKey = responseBody.getJSONObject("data").getString("secretKey");
            redisTemplate.opsForValue().set(YSCONFIGDO.getSecretKey(),secretKey,expireTime, TimeUnit.MILLISECONDS);
//            Long ss= redisTemplate.getExpire(YsConfig.iotRedisKey);
//            System.out.println(expireTime+"---"+ss);
        }else {
            throw new Exception("获取token失败");
        }
        return assToken;
    }

    /**
     * 获取设备解密密钥
     * @return
     * @throws Exception
     */
    public String getSecretKey(String deviceSn) throws Exception {
        YsConfigDo YSCONFIGDO = ysConfig.getConfig(deviceSn);

        if(redisTemplate.hasKey(YSCONFIGDO.getSecretKey())){
            return redisTemplate.opsForValue().get(YSCONFIGDO.getSecretKey());
        }
        else {
            getIotAccessToken(deviceSn);
            return redisTemplate.opsForValue().get(YSCONFIGDO.getSecretKey());
        }
    }

    @Async
    public void videoOpen(String deviceSn, HttpServletRequest request){
        try {
            StringBuilder responseStr = new StringBuilder("--"+deviceSn+"-- ");
            MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
            param.add("accessToken",getIotAccessToken(deviceSn));
            param.add("source",deviceSn+":"+1);
            HttpEntity<JSONObject> response = httpClientUtil.iotAssesTokenPostHttp(YsConfig.openChannelNo,param, HttpMethod.POST);
            JSONObject responseBody = response.getBody();
            responseStr.append("->开通通道:"+responseBody.getInteger("code"));
            JSONObject param2 = new JSONObject();
            param2.put("accessToken",getAccessToken(deviceSn));
            param2.put("deviceSerial",deviceSn);
            param2.put("channelNo","1");
            param2.put("isTrust",0);
            response = httpClientUtil.assesTokenPostHttp(YsConfig.surveillanceWay,param2,HttpMethod.POST);
            responseBody = response.getBody();
            responseStr.append("->获取通道详情:"+responseBody.getInteger("code"));
            if (responseBody.getInteger("code")==200){
                try {
                    JSONObject tmp =  responseBody.getJSONObject("data");
                    String validateCode = tmp.getString("ipcValidateCode");
                    param2 = new JSONObject();
                    param2.put("accessToken",getAccessToken(deviceSn));
                    param2.put("deviceSerial",deviceSn);
                    param2.put("isEncrypt","0");
                    validateCode = messageDecrypt(validateCode,getSecretKey(deviceSn));
                    param2.put("validateCode",validateCode);
                    response = httpClientUtil.assesTokenPostHttp(YsConfig.deviceEncrypt,param2,HttpMethod.POST);
                    responseBody = response.getBody();
                    responseStr.append("->视频解密:"+responseBody.getInteger("code"));
                }catch (Exception e){
                }
            }
//        //设置编码格式
//
//
//        //设置活动检测
//        MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
//        param.add("accessToken",getIotAccessToken());
//        param.add("deviceSerial",deviceSn);
//        param.add("enable","1");
//        param.add("channelNo","1");
//        HttpEntity<JSONObject> response = httpClientUtil.iotAssesTokenPostHttp("https://open.ys7.com/api/lapp/device/intelligence/detection/switch/set",param, HttpMethod.POST);
//        JSONObject responseBody = response.getBody();
//        responseStr.append("->活动检测:"+responseBody.getInteger("code"));

            logger.info(responseStr.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 消息解密
     * @param sSrc
     * @param sKey
     * @return
     * @throws Exception
     */
    public static String messageDecrypt(String sSrc, String sKey) throws Exception {
        try {
            byte[] raw = sKey.getBytes("utf-8");
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = Base64.decode(sSrc);//先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            return new String(original, "utf-8");
        } catch (Exception ex) {
            logger.error("AES解密异常:Str"+sSrc+"\nkey:"+sKey);
            throw new Exception("解密失败");
        }
    }

}
