package com.persagy.dmp.rwd.iot.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.rwd.basic.constant.IotUrlConstant;
import com.persagy.dmp.rwd.basic.utils.MeterUtils;
import com.persagy.dmp.rwd.digital.service.IObjectDigitalService;
import com.persagy.dmp.rwd.iot.model.SettingDataModel;
import com.persagy.dmp.rwd.iot.service.SettingIotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * iot-动态参数设定/查询
 * @author:linhuili
 * @date:2021/8/11
 */
@Service
public class SettingIotServiceImpl implements SettingIotService {

    @Autowired
    private CurrentIotServiceImpl currentDataService;

    @Autowired
    private IObjectDigitalService iObjectDigitalService;

    @Value("${persagy.iot.data.server}")
    private String iotDataServer;

    /**
     * 发送控制指令/设定动态参数
     * @param param
     * @return
     */
    @Override
    public List<SettingDataModel> settingDataService(List<SettingDataModel> param) {
        //设定动态参数
        ArrayNode pointValueList = JsonNodeFactory.instance.arrayNode();
        settingParam(param,pointValueList);

        //绑定动态参数
        String projectLocalId = AppContext.getContext().getProjectId().substring(2);
        ObjectNode requestNode = JsonNodeFactory.instance.objectNode();
        requestNode.put("building", projectLocalId);
        requestNode.set("points", pointValueList);

        String url = iotDataServer + IotUrlConstant.POINT_SET_DATA;
        String response = HttpUtil.post(url, requestNode.toString(), 30000);
        JSONObject object = JSONObject.parseObject(response);
        if(object == null){
            return param;
        }

        //返回结果封装
        JSONArray points = object.getJSONArray("points");
        for (Object node : points) {
            JSONObject item = (JSONObject) node;
            String meter = item.getString("meter");
            String funcid = item.getString("funcid")+"";
            for (SettingDataModel model : param) {
                if (model.getMeter().equals(meter) && model.getFunction().equals(funcid)) {
                    // 楼号-表号-功能号-时间作为唯一标识
                    String exeCode = projectLocalId + ":" + meter + ":" + funcid + ":" + item.getString("receivetime");
                    model.setExeCode(exeCode);
                }
            }
        }
        return param;
    }

    /**
     * 动态参数设置
     * @param param
     * @param pointValueList
     */
    private void settingParam(List<SettingDataModel> param,ArrayNode pointValueList){
        //查询虚拟信息点
        Map<String, List<String>> virtualCodeMap = getVirtualCodeMap(param);

        Map<String, Set<String>> virtualPointCache = new HashMap<>(16);
        for (SettingDataModel model : param) {
            model.setStatus("success");

            //查询信息点值
            String objectId = model.getObjectId();
            String infoCode = model.getInfoCode();
            String infoCodeValue = currentDataService.getInfoCodeValue(objectId, infoCode);

            //信息点校验
            if (infoCodeValue == null) {
                model.setStatus("error");
                model.setError("value of infoCode[" + objectId + ":" + infoCode + "] is null");
                continue;
            }

            // 判断信息点的值是不是表号-功能号格式
            if (!MeterUtils.matchFormat(infoCodeValue)) {
                model.setStatus("error");
                model.setError("value of infoCode[" + objectId + ":" + infoCode + "][ " + infoCodeValue + "] 不是正确的表号功能号");
                continue;
            }

            //设置表号功能号
            int idx = infoCodeValue.lastIndexOf("-");
            String meter = infoCodeValue.substring(0, idx);
            String function = infoCodeValue.substring(idx + 1);
            model.setMeter(meter);
            model.setFunction(function);
            ObjectNode point = pointValueList.addObject();
            point.put("meter", meter);
            point.put("funcid", Long.parseLong(function));
            // TODO 要细分类型
            point.put("data", model.getValue());

            //设置虚拟信息点
            if (!virtualPointCache.containsKey(objectId)) {
                List<String> virtualCode = virtualCodeMap.get(objectId);
                if (virtualCode != null && virtualCode.size() > 0) {
                    virtualPointCache.put(objectId, new HashSet<>(virtualCode));
                } else {
                    virtualPointCache.put(objectId, Collections.emptySet());
                }
            }
            Set<String> virtualPointList = virtualPointCache.get(objectId);
            point.put("virtual", virtualPointList.contains(infoCode));
        }
    }

    /**
     * 获取对象信息点虚拟信息点
     * @param param
     * @return
     */
    private Map<String, List<String>> getVirtualCodeMap(List<SettingDataModel> param){
        List<String> ids = param.stream().map(SettingDataModel::getObjectId).collect(Collectors.toList());
        String projectId = AppContext.getContext().getProjectId();
        String groupCode = AppContext.getContext().getGroupCode();
        Map<String, List<String>> map = iObjectDigitalService.queryVirtualCodeMap(projectId, groupCode, ids);
        return map;
    }

    /**
     * 查询指令执行结果
     * @param param
     * @return
     */
    @Override
    public List<SettingDataModel> settingQuery(List<String> param) {
        if (param == null || param.size() == 0) {
            return null;
        }

        //设置查询参数
        String projectLocalId = AppContext.getContext().getProjectId().substring(2);
        ObjectNode requestNode = JsonNodeFactory.instance.objectNode();
        requestNode.put("building", projectLocalId);
        ArrayNode points = requestNode.putArray("points");
        for (String str : param) {
            ObjectNode point = points.addObject();
            String[] split = str.split(":");
            point.put("meter", split[1]);
            point.put("funcid", Integer.parseInt(split[2]));
            point.put("receivetime", split[3]);
        }

        //查询动态参数
        String url = iotDataServer + IotUrlConstant.QUERY_POINT_SET_DATA;
        String response = HttpUtil.post(url, requestNode.toString(), 30000);
        JSONObject object = JSONObject.parseObject(response);
        if(object == null){
            return null;
        }

        //控制指令执行结果封装
        JSONArray responseData = object.getJSONArray("points");
        List<SettingDataModel> list = new LinkedList<>();
        for (Object datum : responseData) {
            JSONObject item = (JSONObject) datum;
            //表号
            String meter = item.getString("meter");
            //功能号
            String function = item.getString("funcid") + "";
            //执行指令
            String receivetime = item.getString("receivetime");
            String exeCode = projectLocalId + ":" + meter + ":" + function + ":" + receivetime;
            SettingDataModel model = new SettingDataModel();
            model.setExeCode(exeCode);
            //指令执行结果
            model.setExeResult(item.getString("status"));
            list.add(model);
        }
        return list;
    }
}
