package com.sagacloud.utils;
/*
 * Author: Jxing
 * Create Time: 2018/12/21
 */

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.endpoints.item.PhysicalObject;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.objects.ObjectType;
import com.sagacloud.utils.qrCode.QRCodeObj;
import com.sagacloud.utils.tables.HBaseTable;
import com.sagacloud.utils.tables.KeyObjRelTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public class JSONCheckUtil {
    private static final Logger log = LoggerFactory.getLogger(JSONCheckUtil.class);

    public static JSONArray checkEquipBatchCreate(String projectId, JSONArray criterias, JSONArray errors) throws Exception {
        if(criterias == null)
            throw new Exception("criterias错误");
        for(int i = 0; i < criterias.size(); ++i){
            JSONObject single = criterias.getJSONObject(i);

        }
        return null;
    }

    /**
     * 检查设备/系统的id, 并将所有要检查的对象类型(大类型和详细类型)返回
     * @param pjId 项目id
     * @param criterias
     * @param errors
     * @return 添加对象的详细类型
     */
    public static Set<String> checkEqSyEcGenerateId(String pjId, JSONArray criterias, JSONArray errors, String typeKey) {
        Set<String> typeSet = new HashSet<>();
        Set<String> idSet = new HashSet<>();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            if(obj == null){
                criterias.remove(i);
                continue;
            }
            String type = getObjectType(pjId, obj, typeKey);
            if(type == null){
                PropertyUtil.moveToError(criterias, i, errors, "类型错误");
                continue;
            }
            String prefix = type.length() == 2 ? "Sy" : type.length() == 4 ? "Eq" : "Ec";
            prefix+=pjId;
            String id = obj.getString("id");
            if(id != null && id.length() > 0){
                // 已有id的对象, 验证id
                if(!DpUtils.checkId(pjId, id) || !prefix.startsWith(id.substring(0, 2))){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id错误");
                    continue;
                }
            }else{
                // 没有id的对象, 生成id添加进对象
                id = DpUtils.generateUUID(prefix, true);
                obj.put("id", id);
            }
            if(idSet.contains(id)){
                PropertyUtil.moveToError(criterias, i, errors, "id重复", id);
                continue;
            }
            typeSet.add(type);
            idSet.add(id);
        }
        return typeSet;
    }
    /**
     * 检查空间的id, 并将所有要检查的对象类型(大类型和详细类型)返回
     * @param pjId 项目id
     * @param criterias
     * @param errors
     * @return 添加对象的详细业务空间类型
     */
    public static Set<String> checkSpGenerateId(String pjId, JSONArray criterias, JSONArray errors) {
        Set<String> typeSet = new HashSet<>();
        Set<String> idSet = new HashSet<>();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            if(obj == null){
                criterias.remove(i);
                continue;
            }
            String type = obj.getString(Const.BUSINESS_TYPE);
            if(type != null && !PhysicalObject.bussinessSpaceTypeMap.containsKey(type)){
                PropertyUtil.moveToError(criterias, i, errors, "业务空间类型错误");
                continue;
            }
            if(type == null){
                obj.put(Const.BUSINESS_TYPE, "GeneralZone");
                type = "GeneralZone";
            }
            String prefix = String.join("", Const.OBJ_TYPE_SPACE, pjId);
            String id = obj.getString("id");
            if(id != null && id.length() > 0){
                // 已有id的对象, 验证id
                if(!DpUtils.checkId(pjId, id) || !prefix.startsWith(id.substring(0, 2))){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id错误");
                    continue;
                }
            }else{
                // 没有id的对象, 生成id添加进对象
                id = DpUtils.generateUUID(prefix, true);
                obj.put("id", id);
            }
            if(idSet.contains(id)){
                PropertyUtil.moveToError(criterias, i, errors, "id重复");
                continue;
            }
            typeSet.add(type);
            idSet.add(id);
        }
        return typeSet;
    }
    /**
     * 检查空间的id, 并将所有要检查的对象类型(大类型和详细类型)返回
     * @param pjId 项目id
     * @param criterias
     * @param errors
     * @return 添加对象的详细业务空间类型
     */
    public static void checkSiGenerateId(String pjId, JSONArray criterias, JSONArray errors) {
        Set<String> idSet = new HashSet<>();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            if(obj == null){
                criterias.remove(i);
                continue;
            }
            String prefix = String.join("", Const.OBJ_TYPE_ISPACE, pjId);
            String id = obj.getString("id");
            if(id != null && id.length() > 0){
                // 已有id的对象, 验证id
                if(!DpUtils.checkId(pjId, id) || !prefix.startsWith(id.substring(0, 2))){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id错误");
                    continue;
                }
            }else{
                // 没有id的对象, 生成id添加进对象
                id = DpUtils.generateUUID(prefix, true);
                obj.put("id", id);
            }
            if(idSet.contains(id)){
                PropertyUtil.moveToError(criterias, i, errors, "id重复");
                continue;
            }
            idSet.add(id);
        }
    }
    private static String getObjectType(String pjId, JSONObject obj, String typeKey) {
        String category = obj.getString(typeKey);
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        if(eqStaticInfo.getSysSet().contains(category) || eqStaticInfo.getEqSet().contains(category)|| eqStaticInfo.getEcSet().contains(category)){
            return category;
        }
        if(PhysicalObject.bussinessSpaceTypeMap.containsKey(category))
            return category;
        return null;
    }

    public static void verifyEquipInfos(String pjId, JSONArray criterias, HashMap<String, HashMap<String, InfoPoint>> infoCodeMap, String typeKey, JSONArray errors) {
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            String type = getObjectType(pjId, obj, typeKey);
            HashMap<String, InfoPoint> infoMap = infoCodeMap.get(type);
            JSONObject infos = obj.getJSONObject("infos");
            validInfoCode(criterias, errors, i, type, infoMap, infos);
        }
    }
    
    public static void verifyEqInfos(String pjId, JSONArray criterias, HashMap<String, HashMap<String, InfoPoint>> infoCodeMap, String typeKey, JSONArray errors) {
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            String type = getObjectType(pjId, obj, typeKey);
            HashMap<String, InfoPoint> infoMap = infoCodeMap.get(type);
            JSONObject infos = obj.getJSONObject("infos");
            
            if(infos == null || infos.size() == 0){
                obj.put("infos", new JSONObject());
                continue;
            }
            if(infoMap == null || infoMap.size() == 0){
                PropertyUtil.moveToError(criterias, i, errors, String.join("","服务器未获取到", type, "的信息点"));
                continue;
            }
            
            Set<String> nouseInfoSet = new HashSet<>();
            for(String infoCode : infos.keySet()){
                if(!(infoMap.containsKey(infoCode) || EqStaticInfo.propertyGeneralInfos.contains(infoCode))){
                	nouseInfoSet.add(infoCode);
                    continue;
                }
                Object singleInfo = infos.get(infoCode);
                if(!checkSingleInfoFormat(singleInfo)){
                    PropertyUtil.moveToError(criterias, i, errors, String.join("", infoCode, "信息点格式错误"));
                    break;
                }
            }
            
            for(String infoCode : nouseInfoSet) {
            	infos.remove(infoCode);
            }
        }
    }

    public static boolean validInfoCodeRemoveNoUse(JSONArray criterias, JSONArray errors, int i, String type, HashMap<String, InfoPoint> infoMap, JSONObject infos) {
        JSONObject obj = criterias.getJSONObject(i);
        if(infos == null || infos.size() == 0){
            obj.put("infos", new JSONObject());
            return false;
        }
        if(infoMap == null || infoMap.size() == 0){
            PropertyUtil.moveToError(criterias, i, errors, String.join("","服务器未获取到", type, "的信息点"));
            return false;
        }
        
        Set<String> nouseInfoSet = new HashSet<>();
        for(String infoCode : infos.keySet()){
            if(!(infoMap.containsKey(infoCode) || EqStaticInfo.propertyGeneralInfos.contains(infoCode))){
            	nouseInfoSet.add(infoCode);
                continue;
            }
            Object singleInfo = infos.get(infoCode);
            if(!checkSingleInfoFormat(singleInfo)){
                PropertyUtil.moveToError(criterias, i, errors, String.join("", infoCode, "信息点格式错误"));
                return false;
            }
        }
        for(String infoCode : nouseInfoSet) {
        	infos.remove(infoCode);
        }
        return true;
    }

    public static boolean validInfoCode(JSONArray criterias, JSONArray errors, int i, String type, HashMap<String, InfoPoint> infoMap, JSONObject infos) {
        JSONObject obj = criterias.getJSONObject(i);
        if(infos == null || infos.size() == 0){
            obj.put("infos", new JSONObject());
            return false;
        }
        if(infoMap == null || infoMap.size() == 0){
            PropertyUtil.moveToError(criterias, i, errors, String.join("","服务器未获取到", type, "的信息点"));
            return false;
        }
        for(String infoCode : infos.keySet()){
            if(!(infoMap.containsKey(infoCode) || EqStaticInfo.propertyGeneralInfos.contains(infoCode))){
                PropertyUtil.moveToError(criterias, i, errors, String.join("","未识别的信息点", infoCode));
                return false;
            }
            Object singleInfo = infos.get(infoCode);
            if(!checkSingleInfoFormat(singleInfo)){
                PropertyUtil.moveToError(criterias, i, errors, String.join("", infoCode, "信息点格式错误"));
                return false;
            }
        }
        return true;
    }
    
    private static boolean checkSingleInfoFormat(Object singleInfo) {
        if(singleInfo == null || !(singleInfo instanceof JSONArray)){
           return false;
        }
        JSONArray arr = (JSONArray) singleInfo;
        for(int i = 0; i < arr.size(); ++i){
            Object singleInfoObj = arr.get(i);
            if(singleInfoObj == null || !(singleInfoObj instanceof JSONObject))
                return false;
            JSONObject singleObj = (JSONObject) singleInfoObj;
            if(!singleObj.containsKey("value")){
                return false;
            }
        }
        return true;
    }

    public static void countEquipRelation(String pjId, Map<String, String> buildingMap, Map<String, String> floorMap, Map<String, String> equipMap, JSONArray criterias, JSONArray errors) {
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject singleObj = criterias.getJSONObject(i);
            String id = singleObj.getString("id");
            String floorId = singleObj.getString("floor_id");
            String buildId = singleObj.getString("building_id");
            String equipId = singleObj.getString("equip_id");
            if(floorId!= null && DpUtils.checkId(pjId, floorId)){
                floorMap.put(id, floorId);
            }
            if(buildId!= null && DpUtils.checkId(pjId, buildId)){
                buildingMap.put(id, buildId);
            }
            if(equipMap != null && DpUtils.checkId(pjId, equipId)){
                equipMap.put(id, equipId);
            }
        }
    }

    public static void addQRCodeInfo(String pjId, JSONArray criterias, String qrInfoCodeName, Map<String, String> idFileKeyMap) {
        if(!QRCodeObj.autoGenerateQRCode) {
            return;
        }
        Map<String, String> toSave = new HashMap<>();
        for(int i = 0; i < criterias.size(); ++i){
            JSONObject singleObj = criterias.getJSONObject(i);
            String id = singleObj.getString("id");
            JSONObject infos = singleObj.getJSONObject("infos");
            if(infos.containsKey(qrInfoCodeName))
                continue;
            JSONArray qrCodeInfo = new JSONArray();
            JSONObject singleValue = new JSONObject();
            String key = String.join("", id, "QR");

            //指定二维码key，不使用对象id
            String qrKey = singleObj.getString("qrKey");
            if(qrKey != null && qrKey.trim().length() > 0){
                key = qrKey;
                toSave.put(key, id);
            }
            singleValue.put("value", key);
            qrCodeInfo.add(singleValue);
            infos.put(qrInfoCodeName, qrCodeInfo);
            idFileKeyMap.put(id, key);
        }
        //保存二维码key和对象关系到数据库
        saveKeyObj(pjId, toSave);
    }

    private static void saveKeyObj(String pjId, Map<String, String> toSave){
        if(pjId.trim().startsWith("Pj")){
            pjId = pjId.replace("Pj", "");
        }
        final String pId = pjId;
        JSONArray insertObjs = new JSONArray();
        toSave.forEach((k,v) -> {
            insertObjs.add(new JSONObject().fluentPut(KeyObjRelTable.KEY_PJ_ID, pId).fluentPut(KeyObjRelTable.KEY_KEY, k)
            .fluentPut(KeyObjRelTable.KEY_OBJ_ID, v));
        });
        try {
            CommonUtil.insert(true, HBaseTable.key_obj_rel, insertObjs);
        } catch (Exception e) {
            log.error("", e);
        }
    }

    public static void remindErrorRelation(Map<String, Set<String>> failureRelationNodeList, JSONArray success) {
        for(int i = 0; i < success.size(); ++i){
            JSONObject single = success.getJSONObject(i);
            String id = single.getString("id");
            if(failureRelationNodeList.containsKey(id)){
                Set<String> errorIdSet = failureRelationNodeList.get(id);
                if(errorIdSet == null || errorIdSet.size() == 0)
                    continue;
                StringBuilder sb = new StringBuilder();
                sb.append("与");
                for(String errorId : errorIdSet){
                    sb.append(errorId).append(",");
                }
                sb.deleteCharAt(sb.length() - 1);
                sb.append("的关系添加失败");
                single.put("warnMsg", sb.toString());
            }
        }
    }

    /**
     * 
     * @param pjId
     * @param criterias
     * @param infoCodeMap
     * @param errors
     * @param ignoreNouse 是否对不符合数据字典的信息点进行忽略处理
     */
    public static void verifySpaceInfos(String pjId, JSONArray criterias, HashMap<String, HashMap<String, InfoPoint>> infoCodeMap, JSONArray errors) {
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            String id = obj.getString("id");
            ObjectType ot = id.startsWith("Si")?ObjectType.ispace : ObjectType.space;
            String type;
            if(id.startsWith("Si")){
                type = ObjectType.ispace.name();
            }else{
                type = getObjectType(pjId, obj, Const.BUSINESS_TYPE);
            }
            HashMap<String, InfoPoint> infoMap = infoCodeMap.get(type);
            JSONObject infos = obj.getJSONObject("infos");
        	validInfoCodeRemoveNoUse(criterias, errors, i, type, infoMap, infos);
        }
    }
}
