package com.fastbee.iot.timer;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;

import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.utils.DateUtils;
import com.fastbee.deviceData.api.devlink.service.ZhanLianBaseService;
import com.fastbee.deviceData.api.devlink.service.ZhanLianConfig;
import com.fastbee.iot.domain.DeviceReportInfo;;
import com.fastbee.iot.domain.NgFlowDeviceData;
import com.fastbee.iot.mapper.DeviceReportInfoMapper;
import com.fastbee.iot.mapper.NgFlowDeviceDataMapper;
import com.fastbee.iot.service.INgFlowDeviceDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mijiupro
 */
@Component("waterConservancyFlowDeviceDateTask")
@Slf4j
public class NGFlowDeviceDateTask {
//

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private DeviceReportInfoMapper deviceReportInfoMapper;

    @Autowired
    private NgFlowDeviceDataMapper ngFlowDeviceDataMapper;

    @Autowired
    private INgFlowDeviceDataService ngFlowDeviceDataService;

//    @Autowired
//    private ThreadPoolTaskExecutor taskExecutor;


    private  String ak = "nanyang";

    private  String sk = "VMSMSV4D";

    private  String authId  = "25";

    private  String endpoint = "https://plat.developlink.cloud/prod-api/iot/data/forward";

    public String getAuthEndpoint(){
        return endpoint + getDefaultAuth();
    }


    /**
     * 鉴权参数生成
     */
    public String getDefaultAuth(){
        String sign;
        long time = System.currentTimeMillis();
        String message = "ak=" + ak + "&authId=" + authId + "&time=" + time;
        try {
            SecretKeySpec keySpec = new SecretKeySpec(
                    sk.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(keySpec);
            byte[] rawHmac = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            sign = DatatypeConverter.printHexBinary(rawHmac).toLowerCase();
//            System.err.println("result:"+sign);
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败！ : " + e.getMessage(), e);
        }
        return "?ak="+ak+"&time="+time+"&sign="+sign+"&authId="+authId;
    }

    public String getAuth(ZhanLianConfig zhanLianConfig){
        String ak = zhanLianConfig.getAk();
        String sk = zhanLianConfig.getSk();
        String authId = zhanLianConfig.getAuthId();
        String sign;
        long time = System.currentTimeMillis();
        String message = "ak=" + ak + "&authId=" + authId + "&time=" + time;
        try {
            SecretKeySpec keySpec = new SecretKeySpec(
                    sk.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(keySpec);
            byte[] rawHmac = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            sign = DatatypeConverter.printHexBinary(rawHmac).toLowerCase();
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败！ : " + e.getMessage(), e);
        }
        return "?ak="+ak+"&time="+time+"&sign="+sign+"&authId="+authId;
    }

    /**
     * 基本请求
     * @param body 请求负载
     * @return 请求结果 data
     */
    public JSONObject baseRequest(Map<String,Object> body){
        String jsonStr = JSONUtil.toJsonStr(body);
        String respStr = HttpUtil.post(getAuthEndpoint(), jsonStr);
        JSONObject resp = JSONUtil.parseObj(respStr);
        // System.err.println(resp);
        if(!resp.get("code").toString().equals("200")){
            throw new ServiceException(resp.get("message").toString());
        }
        return resp.getJSONObject("data");
    }




    /**
     * 请求设备实时数据
     * @param deviceId 设备id
     * @return 实时数据
     */
    private JSONObject requestDeviceData(String deviceId) {
        //构建请求体
        HashMap<String, Object> body = new HashMap<>();
        body.put("method","get");
        body.put("path","api/v1/product/device/run_status");
        Map<String,Object> params=new HashMap<>();
        params.put("id", deviceId);
        body.put("params",params);
        return baseRequest(body);
    }

    /**
     * 请求设备统计数据
     * @return 统计数据
     */
    private  JSONObject requestDeviceCount() {
        HashMap<String, Object> body = new HashMap<>();
        body.put("method","get");
        body.put("path","/api/v1/product/device/statistics");
        Map<String,Object> params=new HashMap<>();
        body.put("params",params);
        return baseRequest(body);
    }



    /**
     * 根据设备id请求数据并解析设备实时数据为易于存储的map键值对
     * @param deviceId 设备id
     * @return 实时数据
     */
    public Map<String,String> getDeviceRealTimeData(String deviceId){
        //解析返回数据
        JSONObject data =  requestDeviceData(deviceId);
        //获取设备状态
        JSONObject jsonObjectData = JSONUtil.parseObj(data);
        Object status = jsonObjectData.get("status");
        //获取设备属性以及实时数据值
        Object properties = jsonObjectData.get("properties");
        //获取数据上报时间
        String time = jsonObjectData.get("lastOnlineTime").toString();
        JSONArray propertiesArray = JSONUtil.parseArray(properties);
        //获取设备各项属性实时数据
        //设备属性与值建立map
        Map<String, String> propertiesMap = new HashMap<>();
        propertiesArray.forEach(p -> {
            Object property = JSONUtil.parseObj(p).get("property");
            JSONObject propertyMap = JSONUtil.parseObj(property);
            //属性名称
            String name = propertyMap.get("name").toString();
            //属性key
            String key = propertyMap.get("key").toString();
            //属性值
            String value1 = JSONUtil.parseObj(p).getStr("value");
            String value="" ;
            if(value1!=null){
                value = value1;
            }

            //TODO 属性值历史数据，是否需要
            // Object list = JSONUtil.parseObj(p).get("list");
            //建立属性-值映射关系
            propertiesMap.put(key,value);

        });
        //在线状态
        propertiesMap.put("status",status.toString());
        //设备id
        propertiesMap.put("deviceId",deviceId);
        //上报时间
        propertiesMap.put("realTime",time);

        return propertiesMap;
    }

    /**
     * 获取流量计设备实时数据
     */
    public void getFlowDeviceData() {
        //查询全部流量计设备列表
        List<DeviceReportInfo> list = new LambdaQueryChainWrapper<>(deviceReportInfoMapper)
                .select(DeviceReportInfo::getSerialNumber,DeviceReportInfo::getDeviceId)
                .eq(DeviceReportInfo::getType,2)
                .list();

        //实时数据集合
        List<NgFlowDeviceData> ngFlowDeviceDataList = new ArrayList<>();
        //循环获取设备实时数据
        list.forEach(d->{
            try {
                Map<String, String> deviceRealTimeData = getDeviceRealTimeData(d.getSerialNumber());
                //存储设备实时数据
                NgFlowDeviceData ngFlowDeviceData = new NgFlowDeviceData();
                //拼接累计流量整数部分加小数部分
                String l = deviceRealTimeData.get("sumFlow_l");
                String f = deviceRealTimeData.get("sumFlow_F");
                ngFlowDeviceData.setSumFlow(l+f);
                //瞬时流量
                ngFlowDeviceData.setInFlow(deviceRealTimeData.get("inFlow"));
                //实时时间
                ngFlowDeviceData.setRealTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(deviceRealTimeData.get("realTime")));
                //保存时间
                ngFlowDeviceData.setSaveTime(DateUtils.getNowDate());
                //设备状态
                String status = deviceRealTimeData.get("status");
                ngFlowDeviceData.setStatus(Long.valueOf(status));

                    //维护设备在线状态

                    //设备离线
                    if(status.equals("1")){
                        new LambdaUpdateChainWrapper<>(deviceReportInfoMapper)
                                .set(DeviceReportInfo::getOnLine,0)
                                .eq(DeviceReportInfo::getSerialNumber,d.getSerialNumber())
                                .update();
                    }
                    //设备上线
                    else if (status.equals("2")) {
                        new LambdaUpdateChainWrapper<>(deviceReportInfoMapper)
                                .set(DeviceReportInfo::getOnLine,1)
                                .eq(DeviceReportInfo::getSerialNumber,d.getSerialNumber())
                                .update();
                    }
                //设备编码
                ngFlowDeviceData.setDeviceNumber(d.getSerialNumber());
                //机构id
                ngFlowDeviceData.setDeptId(d.getDeptId());
                //设备在线才保存设备数据
                if(status.equals("2")){
                    ngFlowDeviceDataList.add(ngFlowDeviceData);
                }
            }catch (Exception e){
                log.error("流量计设备数据同步异常");
            }

        });
        //批量插入数据
        boolean saveBatch = ngFlowDeviceDataService.saveBatch(ngFlowDeviceDataList);
    }

    public static void main(String[] args) {
        NGFlowDeviceDateTask ngFlowDeviceDateTask = new NGFlowDeviceDateTask();
        Map<String, String> deviceRealTimeData =ngFlowDeviceDateTask.getDeviceRealTimeData("3855");
        System.err.println(deviceRealTimeData);
    }









}

