package com.sagacloud.endpoints;
/*
 * Author: Jxing
 * Create Time: 2017/11/15
 */

import com.sagacloud.dict.EqStaticInfo;
//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;
import com.alibaba.fastjson.*;
import com.sagacloud.dict.InfosUtil;
import com.sagacloud.utils.*;
import com.sagacloud.utils.jsonHelper.SubsetEntity;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.objectLog.ActivityLogObject;
import com.sagacloud.utils.objectLog.ActivityLogRunnable;
import com.sagacloud.utils.objectLog.ActivityLogUtil;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.ObjectIdName;
import com.sagacloud.utils.objects.ObjectType;
import com.sagacloud.utils.qrCode.QRCodeObj;
import com.sagacloud.utils.qrCode.QRCodeRunnable;
import com.sagacloud.utils.relationUtils.PropertyRelUtil;
import com.sagacloud.utils.relationUtils.RelationBuilder;
import com.sagacloud.utils.relationUtils.SubsetRelationSubmitter;
import com.sagacloud.utils.relationUtils.SubsetUtil;
import com.sagacloud.utils.tables.HBaseTable;
import com.sagacloud.utils.tables.ObjectTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.*;

@Path("component")
public class Component {
    private static final Logger log = LoggerFactory.getLogger(Component.class);

    @Path("/batch/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String batchCreate(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        JSONObject postBody = JSONObject.parseObject(jsonStr);
        return batchCreate(projectId, postBody);
    }
    public static String typeKey = "component_category";
    public String batchCreate(@QueryParam(Const.PROJECT_ID) String projectId, JSONObject postBody){
        try {
            String imageUrl = postBody.getString("innerImageUrl");
            Boolean genPersagyQr = postBody.getBoolean("genPersagyQr");
            if(genPersagyQr == null){
                genPersagyQr = false;
            }
            JSONArray criterias = postBody.getJSONArray("criterias");
            if(criterias == null || criterias.size() == 0){
                return DpUtils.returnJSONArray(new JSONArray(), "");
            }
            JSONArray errors = new JSONArray();
            String pjId = projectId.substring(2);
//            一. 准备数据
//            1. 为每个对象生成id, 或者检验指定的id符不符合规则, 检验是否有重复指定的id.
//            2. 统计  设备/系统/部件 类型, 获取每个类型下的信息点列表. (剔除错误类型)
            Set<String> typeSet = JSONCheckUtil.checkEqSyEcGenerateId(pjId, criterias, errors, typeKey);
            HashMap<String, HashMap<String, InfoPoint>> infoCodeMap = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, typeSet.toArray(new String[0]));
//            3. 通过2获取到的信息点列表, 验证信息点的key是否正确(剔除错误)
//            4. 验证信息点节点的格式是否正确.
            JSONCheckUtil.verifyEquipInfos(projectId, criterias, infoCodeMap, typeKey, errors);
//            5. 统计  building_id, floor_id(仅设备允许), (跳过关系id错误的关系).
            Map<String, String> buildingMap = new HashMap<>();  // id --> building_id
            Map<String, String> floorMap = new HashMap<>();     // id --> floor_id
            Map<String, String> equipMap = new HashMap<>();     // id --> equip_id
            JSONCheckUtil.countEquipRelation(pjId, buildingMap, floorMap, equipMap, criterias, errors); // 填充上面两个Map
//            6. 查看是否有二维码信息点EquipQRCode, 有的话不再插入二维码, 没有的话, 添加二维码信息点, 同时记录id(用于接口返回后添加二维码图片).
            Map<String, String> idFileKeyMap = new HashMap<>();
            JSONCheckUtil.addQRCodeInfo(projectId, criterias, "EquipQRCode", idFileKeyMap);
//            二. 插入数据
//            1. 插入对象表 (将失败的剔除)
            if(criterias.size() == 0)
                return PropertyUtil.returnOnCreation(criterias, errors, "");
            String time = CommonUtil.getTime();
            DpUtils.submitToObjectTable(pjId, criterias, time, errors);
            // 补充信息点数据
            ArrayList<ActivityLogObject> logList = new ArrayList<>();
            for(int i = 0; i < criterias.size(); ++i) {
                JSONObject single = criterias.getJSONObject(i);
                String id = single.getString("id");
                ObjectType ot = ObjectUtil.getObjectTypeById(id);
                String detailedType = single.getString(typeKey);
                InfosUtil.addIdName(pjId, ot, detailedType, single.getJSONObject("infos"), id, new ObjectIdName());
                // 添加要发送到activeMQ的消息
                ActivityLogUtil.addMessageToQueue(pjId, time, logList, id, ot);
            }
            JSONArray success = new JSONArray();
            PropertyUtil.putIDToInfos(criterias, success);

//            2. 插入关系 (失败的话, 提示 关系插入失败, 不剔除)
            RelationBuilder relationBuilder = new RelationBuilder(pjId);
            List<SubsetEntity> entities = new ArrayList<>();
            try {
                SubsetRelationSubmitter srs = new SubsetRelationSubmitter(pjId);
                srs.addFrom2To(buildingMap, true);
                srs.addTo2From(equipMap, true);
                srs.submit();
            }catch (Exception ignore){}
//            relationBuilder.addTo2From(buildingMap, "Subset", "3");
//            relationBuilder.addFrom2To(buildingMap, "Subset", "5");
            relationBuilder.addFrom2To(floorMap, "EquipinFloor", "1");
            boolean hasException = false;
            try {
                relationBuilder.filterInvalidObjects().fillGraphId().insert();
            }catch (Exception ignore){hasException = true;}
            Map<String, Set<String>> failureRelationMap = null;
            if(hasException) {
                failureRelationMap = relationBuilder.getErrorMap(relationBuilder.getData(), relationBuilder.getError(), "Ec");
            }else{
                failureRelationMap = relationBuilder.getErrorMap(null, relationBuilder.getError(), "Ec");
            }
            JSONCheckUtil.remindErrorRelation(failureRelationMap, success);
//            3. 插入信息点
            ObjectUtil.batchUpdate(pjId, criterias, false, true, false, new CommonQueryCriteria());
//            三. 接口返回后
//            1. 发送activeMQ消息, 记录日志
            ActivityLogRunnable activityLog = new ActivityLogRunnable(logList);
            ActivityLogUtil.pool.submit(activityLog);
//            2. 生成二维码文件, 上传到文件服务器
            QRCodeRunnable qrCodeRunnable = new QRCodeRunnable(idFileKeyMap, imageUrl, projectId, genPersagyQr);
            ActivityLogUtil.pool.submit(qrCodeRunnable);
            return PropertyUtil.returnOnCreation(success, errors, "");
        }catch (Exception ex)
        {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage() == null? "添加失败!": ex.getMessage());
        }
    }
    @Path("/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String createSingle(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        JSONObject postObj = JSONObject.parseObject(jsonStr);
        JSONObject postBody = new JSONObject();
        JSONArray criterias = new JSONArray();
        criterias.add(postObj);
        postBody.put("criterias", criterias);
        String result = batchCreate(projectId, postBody);
        JSONObject criteria = JSONObject.parseObject(result);
        return DpUtils.batchToSingle(criteria);
    }


    @Path("/create_old")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String create(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject insertJson = JSONObject.parseObject(jsonStr);
            if (!insertJson.containsKey("component_category") || !insertJson.containsKey(Const.JSON_FIELD_JSON_DATA_INFOS)) {
                return DpUtils.errorJsonMsg("缺少必要字段");
            }
            String equip_id = null;
            String category = insertJson.get("component_category").toString();
            if(insertJson.get("equip_id") != null){
                equip_id = insertJson.get("equip_id").toString();
                // check if eq exist
                JSONObject checkCriteria = new JSONObject();
                checkCriteria.put(ObjectTable.KEY_PJ_ID, projectId.substring(2));
                checkCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_EQUIPMENT);
                checkCriteria.put(ObjectTable.KEY_OBJ_ID, equip_id.substring(12));
                checkCriteria.put(Const.TABLE_KEY_NAME_VALID, true);
                JSONObject eqObj = this.getJsonObject(HBaseTable.objects, checkCriteria);
                if(eqObj == null)
                    throw new Exception("设备不存在.");
                // check end.
                if(!category.startsWith(eqObj.get(ObjectTable.COL_SUBTYPE).toString())){
                    throw new Exception("设备类型和部件类型不匹配");
                }
            }

            String assignedObjId = null;
            if(insertJson.get("id") != null)
            {
                String id = insertJson.get("id").toString();
                if(id.startsWith("Ec")) {
                    assignedObjId = id.substring(12);
                    if (!DpUtils.verifyAssignedObjID(assignedObjId)) {
                        return DpUtils.errorJsonMsg("指定的id错误.");
                    }
                }else
                    return DpUtils.errorJsonMsg("指定的id错误.");
            }
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            if (!eqStaticInfo.getEcSet().contains(category))
                throw new Exception("部件类型不存在");

            String id = null;
            ObjectIdName name = new ObjectIdName();
            id = ObjectUtil.addObj(projectId.substring(2), Const.OBJ_TYPE_EQUIPMENT_COMPONENT, category,
                    (JSONObject) insertJson.get(Const.JSON_FIELD_JSON_DATA_INFOS), ObjectType.component, name, assignedObjId, false);
            if(equip_id != null){
                //insert equipment-component relation
                SubsetUtil.addRel(projectId, equip_id, id);
            }
            return DpUtils.successJsonMsgWithId("", id, name.getNameKey(), name.getNameValue());
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage() == null ? "添加失败!" : ex.getMessage());
        }
    }

    private  JSONObject getJsonObject(HBaseTable table, JSONObject criteria) throws Exception{
        JSONObject json = JSONObject.parseObject("{\"QueryType\":\"select\"}");
        json.put("Database", OssUtils.getProperty("database.name"));
        json.put(Const.JSON_FIELD_CRITERIA, criteria);
        json.put(Const.FIELD_TABLE_NAME, table.name());
        JSONArray content = (JSONArray) ZillionAgentProvider.GetAgent().Query(json).get("Content");
        if(content.size() == 0){
            return  null;
        }else{
            return (JSONObject) content.get(0);
        }
    }

    @Path("/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String delete(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try
        {
            JSONObject criteria =  JSONObject.parseObject(jsonStr).getJSONObject("criteria");
            if(criteria.get("id") == null || !criteria.get("id").toString().startsWith("Ec"))
                throw new Exception("Id错误");
            String id = criteria.get("id").toString();
            CommonUtil.rewriteObjectTableCriteria(projectId.substring(2), criteria, "id", false);
            CommonUtil.deleteObject(id, criteria.get(ObjectTable.KEY_PJ_ID).toString(), criteria.get(ObjectTable.KEY_OBJ_TYPE).toString()
                    ,criteria.get(ObjectTable.KEY_OBJ_ID).toString(), ObjectType.component, true);
            Set<String> idSet = new HashSet<>();
            idSet.add(id);
            PropertyRelUtil.deleteLinkByEq(projectId, idSet);
            return DpUtils.successJsonMsg("");
        }catch (Exception ex)
        {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }
}
