package com.demo.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.demo.common.SpecialSecret;
import com.demo.constant.OSEnum;
import com.demo.dao.*;
import com.demo.entity.dto.DeviceReturnDto;
import com.demo.entity.po.*;
import com.demo.entity.vo.DeviceConfVo;
import com.demo.entity.vo.DeviceIdVo;
import com.demo.entity.vo.SensorVo;
import com.reyun.Algorithm;
import com.demo.util.DeformedBase64;
import com.demo.util.RSAUtil;
import com.demo.util.SecretUtil;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
public class DeviceService {

    private final Logger logger = LoggerFactory.getLogger(DeviceService.class);

    private final int keyLenth = 128;//aes长度

    @Autowired
    private SecretDao  secretDao;
    @Autowired
    private DeviceInfoDao deviceInfoDao;
    @Autowired
    private DeviceConfDao deviceConfDao;
    @Autowired
    private SensorInfoDao sensorInfoDao;
    @Autowired
    private BusinDataDao businDataDao;
    @Autowired
    private HeartBeatDao heartBeatDao;

//    /**
//     *
//     * 获取机器的配置信息
//     * @param deviceConfVo
//     * @return
//     */
//    public DeviceReturnDto getDeviceConf(DeviceConfVo deviceConfVo){
//
//         Secret secret = getSecret(deviceConfVo.getGorganization());
//         if(secret == null){
//             logger.info("getDeviceConf 获取密钥失败:{}", JSONObject.toJSONString(deviceConfVo));
//             return null;
//         }
//
//         // 统一转成小写
//        String os = deviceConfVo.getOs().toLowerCase();
//
//         //组装DeviceConfDataDto
//        List<RiskApp> riskApps = riskAppDao.findAll(os);
//        List<RiskDir> riskDirs = riskDirDao.findAll(os);
//        List<RiskFile> riskFiles = riskFileDao.findAll(os);
//        if(os.equals("ios")){//ios的相对安卓多出一项配置(TODO 后续补上)
//
//        }
//        UpdateInfo updateInfo = updateInfoDao.findEnable();
//
//        DeviceConf deviceConf = deviceConfDao.findEnable();
//        if(deviceConf == null){
//            logger.info("getDeviceConf 配置信息找不到");
//        }
//
//        List<String> whiteApps = deviceConf != null ? Arrays.asList(deviceConf.getWhite_apps().split(",")) : null;
//        Integer priod = deviceConf != null ? deviceConf.getPeriod() : null;
//        Boolean riskFileSwitch = deviceConf != null ? deviceConf.getRisk_file_switch() : null;
//        DeviceConfDataDto deviceConfDataDto = new DeviceConfDataDto(riskApps, riskDirs,
//                riskFileSwitch, riskFiles, updateInfo, whiteApps, priod);
//
//        String data = JSONObject.toJSONString(deviceConfDataDto);
//        DeviceReturnDto deviceReturnDto = new DeviceReturnDto(data, data.length(),
//                SpecialSecret.getSecretAesStr(secret.getAesKey(), secret.getPrivateRsaKey()),
//                SpecialSecret.getSecretRSAStr(secret.getPublicRsaKey()));
//        return deviceReturnDto;
//
//    }

    /**
     *
     * 获取机器的配置信息
     * @param deviceConfVo
     * @return
     */
    public String getDeviceConf(DeviceConfVo deviceConfVo){

        if(StringUtils.isEmpty(deviceConfVo.getGorganization())
                || StringUtils.isEmpty(deviceConfVo.getOs())){
            logger.info("getDeviceConf 缺少参数:{}", JSONObject.toJSONString(deviceConfVo));
            return  null;
        }

        Secret secret = getSecret(deviceConfVo.getGorganization());
        if(secret == null){
            logger.info("getDeviceConf 获取密钥失败:{}", JSONObject.toJSONString(deviceConfVo));
            return null;
        }

        // 统一转成小写
        OSEnum osEnum = OSEnum.getOS(deviceConfVo.getOs());

         DeviceConf deviceConf = deviceConfDao.findEnable(osEnum.getVal());
        if(deviceConf == null){
            logger.info("getDeviceConf 获取配置信息失败:{}", JSONObject.toJSONString(deviceConfVo));
            return null;
        }
        JSONObject data = deviceConf.getConfInfo();
        try{
            logger.info("secret.getAesKey():{}  secret.getPrivateRsaKey():{}", secret.getAesKey(), secret.getPrivateRsaKey());

            DeviceReturnDto deviceReturnDto = new DeviceReturnDto(data, data.toJSONString().length(),
                    SpecialSecret.getSecretAesStr(secret.getAesKey(), secret.getPrivateRsaKey()),
                    SpecialSecret.getSecretRSAStr(secret.getPublicRsaKey()));

            return  DeformedBase64.encode(JSONObject.toJSONString(deviceReturnDto));
        }catch (Exception e){
            logger.info("getDeviceConf 获取dll动态库失败:{}", JSONObject.toJSONString(deviceConfVo));
        }

        return  null;

    }


    /**
     *TODO 需要考虑设备怎么唯一
     * 获取设备唯一id
     * @param deviceIdVo
     * @return
     */
    public String getDeviceId(DeviceIdVo deviceIdVo){

        if(StringUtils.isEmpty(deviceIdVo.getData()) || StringUtils.isEmpty(deviceIdVo.getOs())
                || StringUtils.isEmpty(deviceIdVo.getGorganization())){
            logger.info("getDeviceId 传递的参数有误:{}", JSONObject.toJSONString(deviceIdVo));
            return null;
        }

        OSEnum osEnum = OSEnum.getOS(deviceIdVo.getOs());
        if(osEnum == null){
            logger.info("getDeviceId 传递的Os参数有误:{}", JSONObject.toJSONString(deviceIdVo));
            return null;
        }
        //获取密钥
        Secret secret = getSecret(deviceIdVo.getGorganization());
        if(secret == null){
            logger.info("getDeviceId 获取密钥失败:{}", JSONObject.toJSONString(deviceIdVo));
            return  null;
        }

        //解密data
        String data = SpecialSecret.getData(deviceIdVo.getData(), secret.getAesKey());

        if(StringUtils.isEmpty(data)){
            logger.info("getDeviceId 传递的data参数有误:{}", JSONObject.toJSONString(deviceIdVo));
            return null;
        }
        JSONObject dataObject = JSON.parseObject(data);
        if(dataObject == null){
            logger.info("getDeviceId 传递的data参数有误.无法转化json:{}", JSONObject.toJSONString(deviceIdVo));
            return null;
        }

        //返回唯一值
        Map<String, String> reyunIdMap = new HashMap<>();
        String clientReyunId = dataObject.getString("reyunId");
        if(StringUtils.isEmpty(clientReyunId)){
            logger.info("getDeviceId 传递的data参数有误,reyunId取不到:{}", JSONObject.toJSONString(deviceIdVo));
            return null;
        }
        String deviceId = "";//iOS取IDFA,Android则按照优先级imei/android_id取一个
        if(osEnum == OSEnum.IOS){
            deviceId = dataObject.getString("idfa");
        }else{
            deviceId = dataObject.getString("DeviceID");
            if(StringUtils.isEmpty(deviceId)){
                deviceId = dataObject.getString("AndroidID");
            }
        }
        String reyunId = getReyunId(clientReyunId, deviceId, secret.getPublicRsaKey());
        String reyunIdReal = reyunId.replaceAll("\\\\","");//去掉\反义字符,防止后面转化的时候导致不一致
        reyunIdMap.put("reyunId", reyunIdReal);

        //区分系统保存数据
        //去掉转义字符
        data = StringUtils.isEmpty(data) ? data : data.replaceAll("\n","");
        String dataReal =  StringEscapeUtils.unescapeJavaScript(data);
        JSONObject jsonData = JSONObject.parseObject(dataReal);

        DeviceInfo deviceInfo = new DeviceInfo(osEnum.getVal(), jsonData, reyunIdReal);
//        System.out.println("/deviceid 将要保存的数据:"+JSONObject.toJSONString(deviceInfo));
        deviceInfoDao.insert(deviceInfo);

        JSONObject result = (JSONObject) JSON.toJSON(reyunIdMap);

        try{
            DeviceReturnDto deviceReturnDto = new DeviceReturnDto(result, result.toJSONString().length(),
                    SpecialSecret.getSecretAesStr(secret.getAesKey(), secret.getPublicRsaKey()),
                    SpecialSecret.getSecretRSAStr(secret.getPublicRsaKey()));

            String resultStr = SpecialSecret.aesData(JSONObject.toJSONString(deviceReturnDto), secret.getAesKey());
            return resultStr;
        }catch (Exception e){
            logger.info("getDeviceId 获取dll动态库失败:{}", JSONObject.toJSONString(deviceIdVo));
        }

        return null;
    }


    private String getReyunId(String clientReyunId, String deviceId, String publicKey ){
        String defaultReyunId = "defaultone";
        long timestamp = new Date().getTime();
        Algorithm alg = new Algorithm();
        String shaStr = alg.sha1(clientReyunId + timestamp + deviceId)+defaultReyunId;
        return  DeformedBase64.encode(alg.rsaEncode(shaStr, publicKey));
    }

//    /**
//     *TODO 需要考虑设备怎么唯一
//     * 获取设备唯一id
//     * @param deviceIdVo
//     * @return
//     */
//    public DeviceReturnDto getDeviceId(DeviceIdVo deviceIdVo){
//
//        //解密data
//        String data = DeformedBase64.decode(deviceIdVo.getData());
//        Object dataObject = JSON.parse(data);
//        if(dataObject == null){
//            logger.info("getDeviceId 传递的data参数有误:{}", JSONObject.toJSONString(deviceIdVo));
//            return null;
//        }
//
//        //区分系统保存数据
//        if("ios".equalsIgnoreCase(deviceIdVo.getOs())){
//            DeviceInfoIos deviceInfoIos = (DeviceInfoIos)dataObject;
//            deviceInfoIosDao.insert(deviceInfoIos);
//        }else if("android".equalsIgnoreCase(deviceIdVo.getOs())){
//            DeviceInfoAndroid deviceInfoAndroid = (DeviceInfoAndroid)dataObject;
//            deviceInfoAndroidDao.insert(deviceInfoAndroid);
//        }else{
//            logger.info("getDeviceId 传递的os参数有误:{}", JSONObject.toJSONString(deviceIdVo));
//            return  null;
//        }
//
//        //返回唯一值(TODO 此处写成uuid形式,后面需要时间允许按照规则编写)
//        Map<String, String> reyunIdMap = new HashMap<>();
//        reyunIdMap.put("reyunId",UUID.randomUUID()+"");
//
//        Secret secret = getSecret(deviceIdVo.getGorganization());
//        if(secret == null){
//            logger.info("getDeviceId 获取密钥失败:{}", JSONObject.toJSONString(deviceIdVo));
//            return  null;
//        }
//
//        String dataStr = JSONObject.toJSONString(reyunIdMap);
//        DeviceReturnDto deviceReturnDto = new DeviceReturnDto(dataStr, dataStr.length(),
//                SpecialSecret.getSecretAesStr(secret.getAesKey(), secret.getPrivateRsaKey()),
//                SpecialSecret.getSecretRSAStr(secret.getPublicRsaKey()));
//
//        return deviceReturnDto;
//    }

//    public Boolean reciveSensorInfo(SensorVo sensorVo){
//
//        //解密data
//        String data = DeformedBase64.decode(sensorVo.getData());
//        Object dataObject = JSON.parse(data);
//        if(dataObject == null){
//            logger.info("reciveSensorInfo 传递的data参数有误:{}", JSONObject.toJSONString(sensorVo));
//            return false;
//        }
//
//        //区分系统保存数据
//        if("ios".equalsIgnoreCase(sensorVo.getOs())){
//            SensorInfo sensorInfoIos = (SensorInfo) dataObject;
//            sensorInfoIosDao.insert(sensorInfoIos);
//        }else if("android".equalsIgnoreCase(sensorVo.getOs())){
//            SensorInfoAndroid sensorInfoAndroid = (SensorInfoAndroid) dataObject;
//            sensorInfoAndroidDao.insert(sensorInfoAndroid);
//        }else{
//            logger.info("reciveSensorInfo 传递的os参数有误:{}", JSONObject.toJSONString(sensorVo));
//            return  false;
//        }
//        return true;
//    }

    public Boolean reciveSensorInfo(SensorVo sensorVo){

        //获取密钥
        Secret secret = getSecret(sensorVo.getGorganization());
        if(secret == null){
            logger.info("reciveSensorInfo 获取密钥失败:{}", JSONObject.toJSONString(sensorVo));
            return  null;
        }

        //解密data
        String data = SpecialSecret.getData(sensorVo.getData(), secret.getAesKey());
        if(StringUtils.isEmpty(data)){
            logger.info("reciveSensorInfo 传递的data参数有误:{}", JSONObject.toJSONString(sensorVo));
            return false;
        }
        JSONObject dataObject = JSON.parseObject(data);
        if(dataObject == null){
            logger.info("reciveSensorInfo 传递的data参数有误.无法转化json:{}", JSONObject.toJSONString(sensorVo));
            return null;
        }

        OSEnum osEnum = OSEnum.getOS(sensorVo.getOs());

        //保存数据
        String reyunId = dataObject.getString("reyunId");
        //去掉转义字符
        data = StringUtils.isEmpty(data) ? data : data.replaceAll("\n","");
        String dataReal =  StringEscapeUtils.unescapeJavaScript(data);
        JSONObject dataJson = JSONObject.parseObject(dataReal);
        SensorInfo sensorInfo = new SensorInfo(reyunId, new Date().getTime(), dataJson, osEnum.getVal());
        sensorInfoDao.insert(sensorInfo);
        return true;
    }

    /**
     * 获取私钥公钥
     * @param gorganization
     * @return
     */
    private Secret getSecret(String gorganization){
        Secret secret =  secretDao.findEnableSecret(gorganization);
        if(secret == null){
            try{
                Map<String, Object> keyMap = RSAUtil.initKey(gorganization);
                String publicKey = RSAUtil.getPublicKey(keyMap);
                String privateKey = RSAUtil.getPrivateKey(keyMap);
                String aeskey = SecretUtil.generateAesKey(keyLenth, gorganization);
                secret = new Secret(gorganization, publicKey, privateKey, aeskey, new Date().getTime(), true);
                secretDao.insert(secret);
            }catch (Exception e){
                logger.info("生成rsa公钥私钥失败-gorganization:{},-exception:{}",gorganization, e);
                return null;
            }
        }
        return  secret;
    }

    public void insertBusinData(BusinData data){
        businDataDao.insert(data);
    }


    public void insertHeartBeat(HeartBeat heartBeat){
        heartBeatDao.insert(heartBeat);
    }

    public String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if( ip.indexOf(",")!=-1 ){
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}