package com.sagacloud.endpoints;

import com.sagacloud.cache.utils.CacheUtil;
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.utils.*;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.PhysicalWorldObject;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.jsonHelper.property.PropertyRel;
import com.sagacloud.utils.relationUtils.PropertyRelUtil;
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.*;

/*
 * Author: Jxing
 * Create Time: 2018/3/8
 */
@Path("property")
public class Property {
    private static final Logger log = LoggerFactory.getLogger(Property.class);
    @Path("/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String create(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyCreateSchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject object = JSONObject.parseObject(jsonStr);
        JSONArray arr = (JSONArray) object.get("criterias");
        JSONArray errors = new JSONArray();
        JSONArray success = new JSONArray();
        boolean skipErrorInfo = false; // 当有信息点不属于指定种族时的时候, 跳过错误信息点, 默认false是不跳过
        if(object.get("skipErrorInfo") != null && object.get("skipErrorInfo").equals(true))
            skipErrorInfo = true;
        String qrInnerImageUrl = object.getString("innerImageUrl");
        Boolean genPersagyQr = object.getBoolean("genPersagyQr");
        if(genPersagyQr == null){
            genPersagyQr = false;
        }
        // 检验是否关联的对象属于该项目, 不属于则剔除
        String project = projectId.substring(2);
        for(int i = arr.size() - 1; i > -1; --i)
        {
            JSONObject single = (JSONObject) arr.get(i);
            JSONObject relation = (JSONObject) single.get("relation");
            if(relation != null && (relation.get("link")!= null ||relation.get("building") != null || relation.get("floor")!= null))
            {
                for(String key : relation.keySet())
                {
                    if (!relation.get(key).toString().startsWith(project, 2)) // 所有id均是本项目下的
                    {
                        PropertyUtil.moveToError(arr, i, errors, String.join("", key, "错误!"));
                        continue;
                    }
                }
            }
        }
        String resultMsg = PropertyUtil.addObj(project, arr, errors, success, skipErrorInfo, true, qrInnerImageUrl, genPersagyQr);
        return PropertyUtil.returnOnCreation(success, errors, resultMsg == null?"" : resultMsg);
    }

    @Path("/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String delete(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyDeleteSchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject obj = JSONObject.parseObject(jsonStr);
        JSONArray objects = (JSONArray) obj.get("criterias");
        JSONArray errors = new JSONArray();
        if(objects.size() == 0)
            return PropertyUtil.returnJSON(false, null, errors, "");
        // 删除
        try {
            PropertyUtil.deletePropertyObjects(projectId.substring(2), objects, errors);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("删除失败");
        }
        if(errors.size() > 0)
            return PropertyUtil.returnJSON(objects.size() != 0, null, errors, "");
        return DpUtils.successJsonMsg("删除成功");
    }

    @Path("/id_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String idQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        // 查id,
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyIdQuerySchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject query = JSONObject.parseObject(jsonStr);
        CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);

        JSONArray criteriasNode = (JSONArray) query.get("criterias");
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        String pjId = projectId.substring(2);
        return querySelfInfos(criteriasNode, cqc, pjId, eqStaticInfo);
    }

    public static String querySelfInfos(JSONArray criteriasNode, CommonQueryCriteria cqc, String pjId, EqStaticInfo eqStaticInfo) {
        JSONArray result;
        try {
            result = CommonUtil.batchQuerySelfInfo(pjId, criteriasNode, cqc, eqStaticInfo);
            if(cqc.getNodata())
                return  DpUtils.returnJSONArray(result, "", cqc.getCount());
            PropertyUtil.getPropertyRelation(pjId, result);
            return  DpUtils.returnJSONArray(result, "");
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }
    // 原来没有用缓存的接口, 不支持limit 和 filter参数
    @Path("/relation_query_old")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String relationQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyRelationQuerySchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject query = JSONObject.parseObject(jsonStr);
        CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);

        JSONObject criteriasNode = (JSONObject) query.get("criteria");
        String pjId = projectId.substring(2);
        if(criteriasNode.get("id") != null)
        {
            if(!DpUtils.checkId(pjId, criteriasNode.get("id").toString()))
                return DpUtils.errorJsonMsg("Id不合法");
        }
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        if(criteriasNode.get("family") != null)
        {
            JSONArray array = (JSONArray) criteriasNode.get("family");

            for(int i = 0; i < array.size(); ++i)
            {
                if(!eqStaticInfo.getFamilySet().contains(array.get(i).toString()))
                    return DpUtils.errorJsonMsg(String.join("", "种族", array.get(i).toString(), "不合法"));
            }
        }

        HashSet<String> ids = null;
        try {
            ids = PropertyUtil.queryByRelation(pjId, criteriasNode);
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
        JSONArray idList = new JSONArray();
        for(String id : ids)
        {
            JSONObject obj = new JSONObject();
            obj.put("id", id);
            idList.add(obj);
        }

        return querySelfInfos(idList, cqc, pjId, eqStaticInfo);
    }

    @Path("/relation_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String relationQueryCached(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyRelationQuerySchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject query = JSONObject.parseObject(jsonStr);
        CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);

        JSONObject criteriasNode = (JSONObject) query.get("criteria");
        String pjId = projectId.substring(2);
        if(criteriasNode.get("id") != null)
        {
            if(!DpUtils.checkId(pjId, criteriasNode.get("id").toString()))
                return DpUtils.errorJsonMsg("Id不合法");
            cqc.setDirectOnlyId(criteriasNode.get("id").toString());
        }else{
            cqc.setDirectOnlyId(projectId);
        }
        if(criteriasNode.get("family") != null)
        {
            JSONArray array = (JSONArray) criteriasNode.get("family");
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            for(int i = 0; i < array.size(); ++i)
            {
                if(!eqStaticInfo.getFamilySet().contains(array.get(i).toString()))
                    return DpUtils.errorJsonMsg(String.join("", "种族", array.get(i).toString(), "不合法"));
            }
        }

        HashSet<String> ids = null;
        try {
            ids = PropertyUtil.queryByRelation(pjId, criteriasNode);
            JSONArray ret = CacheUtil.queryWithPaging(pjId, ids, cqc);
            return DpUtils.returnJSONArray(ret, cqc.getSkip_totalCount());
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
//        JSONArray idList = new JSONArray();
//        for(String id : ids)
//        {
//            JSONObject obj = new JSONObject();
//            obj.put("id", id);
//            idList.add(obj);
//        }
//        return querySelfInfos(idList, cqc, pjId, projectId);
    }

    @Path("/update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String update(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyUpdateSchema.json");
            if(validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject obj = JSONObject.parseObject(jsonStr);
        CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(obj);
        JSONArray objects = (JSONArray) obj.get("criterias");
        JSONArray errors = new JSONArray();
        String pjId = projectId.substring(2);
        HashMap<String, PhysicalWorldObject> validProperty = null;   // key --> 资产id Pe*****, value 它的种族编码
        Map<String, String> equipToDetailType = null;
        boolean skipErrorInfo = false; // 当有信息点不属于指定种族时的时候, 跳过错误信息点, 默认false是不跳过
        if(obj.get("skipErrorInfo") != null && obj.get("skipErrorInfo").equals(true))
            skipErrorInfo = true;
        try {
            // 查看要修改的建筑, 楼层和项目是否冲突.
            PropertyUtil.validateIsIdsSameProject(pjId, objects, errors);
            // 验证种族, 还有要修改的种族和信息点是否对应., 种族和关联设备类型一致没验证
            //equipToDetailType = PropertyUtil.validateFamilyAndInfos(objects, errors);
            equipToDetailType = PropertyUtil.validateFamilyAndInfosSkipErrorInfo(projectId, objects, errors, skipErrorInfo);
            // 先查出来资产, 然后没查到的资产要移到错误列表中.
            validProperty = PropertyUtil.validateExistence(pjId, objects, errors); // 将查到的Object表信息返回.
        } catch (Exception e) {
            if(errors.size() > 0)
                return PropertyUtil.returnJSON(false, null, errors, "服务器异常");
            return PropertyUtil.returnJSON(false, null, null, "服务器异常");
        }
        if(validProperty == null || validProperty.size() == 0)
            return PropertyUtil.returnJSON(false, null, errors, "");
        // 修改项目或种族, 获取原来种族之后, 获得原来种族的信息点, 如果不在新种族中, 则删除该信息点.
        // 修改项目需要修改Objects表的项目和删除楼层和建筑关联
        // 修改种族需要删除objects表中的一行数据, 删除原来独有的信息点. 删除关联资产
        Set<String> peIdSet ;
        try {
            peIdSet = PropertyUtil.updateFamilyAndProject(pjId, validProperty, objects, errors, equipToDetailType, skipErrorInfo);
        } catch (Exception e) {
            log.error("", e);
            return PropertyUtil.returnJSON(false, null, errors, String.join("", "服务器异常", e.getMessage()));
        }
        // 开始修改三种关联
        HashSet<String> peIdWithRelation = new HashSet<>(); // 保存带有关联岗位的peid
        ArrayList<PropertyRel> tmp = PropertyUtil.generateRelationArray(pjId, objects);
        for(String id : peIdSet)
            tmp.add(PropertyUtil.generatePropertyRelation(id, null, Const.OBJ_TYPE_EQUIPMENT, null)); // 删除改变种族后资产和岗位的关联
        PropertyRelUtil.modify(pjId, tmp);
        if(cqc.isSyncInfos()) {
            for (PropertyRel rel : tmp) {
                if (rel.objType != null && rel.objType.equals(Const.OBJ_TYPE_EQUIPMENT) && !peIdWithRelation.contains(rel.propertyId)) {
                    peIdWithRelation.add(rel.propertyId);
                }
            }
            if (peIdWithRelation.size() > 0)
                PropertyUtil.complementInfos(pjId, peIdWithRelation); // 同步信息点
        }
        // 开始修改信息点
        try {
            PropertyUtil.updateNewFamilyInfos(pjId, objects, validProperty, cqc.isCoverInfos());
        } catch (Exception e) {
            log.error("", e);
            return PropertyUtil.returnJSON(false, null, errors, String.join("", "服务器异常", e.getMessage()));
        }
        return PropertyUtil.returnJSON(true, null, errors, "");
    }

    @Path("/create_by_equip")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String createByEquip(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyCreateByEquipSchema.json");
            if (validateInfo != null && validateInfo.length() != 0)
                return DpUtils.errorJsonMsg(validateInfo);
        } catch (Exception ex) {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject obj = JSONObject.parseObject(jsonStr);
        boolean skipErrorInfo = false;
        String id = obj.get("id").toString();
        String floorId = (String) obj.get("floor");
        obj.remove("floor");
        if(!DpUtils.checkId(projectId, id) && (id.startsWith("Eq")||id.startsWith("Ec")))
            return DpUtils.errorJsonMsg("id错误或没有权限!");
        if(floorId != null && (!floorId.startsWith("Fl") || !DpUtils.checkId(floorId)))
            return DpUtils.errorJsonMsg("floor错误");
        // 查询该设备或部件及其信息点, 不存在就返回
        JSONObject equipObj = null;
        try {
            JSONArray arr = new JSONArray();
            arr.add(obj);
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            JSONArray result = CommonUtil.batchQuerySelfInfo(projectId.substring(2), arr, new CommonQueryCriteria(), eqStaticInfo);
            if(result.size() == 0)
                return DpUtils.errorJsonMsg("设备或部件不存在");
            equipObj = (JSONObject) result.get(0);

            // 获取设备id关联的资产, 如果存在关联关系则返回
            HashSet<String> objIdList = new HashSet<>();
            objIdList.add(id);
            HashMap<String, HashSet<String>> propertySets = PropertyRelUtil.queryByObjId(projectId, objIdList);
            if(propertySets.get(id)!= null && propertySets.get(id).size() > 0)
                return DpUtils.errorJsonMsg(String.join("", "Id:", id, "已存在绑定资产"));

        }catch (Exception ex)
        {
            log.error("", ex);
            return DpUtils.errorJsonMsg("添加失败, 服务器异常");
        }

        // 获取资产种族, 从设备信息点中筛选出符合种族信息点的来构建信息点节点, 添加关联, 走添加接口.
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        String family = eqStaticInfo.getEqToFamilyMap().get(CommonUtil.getEquipCategory(id, false));
        if(family == null || family.length() == 0)
            return DpUtils.errorJsonMsg("不存在该设备id的类型对应的种族");
        HashMap<String, HashMap<String, InfoPoint>> infos = null;
        try {
            HashSet<String> familySet = new HashSet<>();
            familySet.add(family);
            infos = InfoCodeUtil.innerGetFamilyInfos(projectId, familySet);
        } catch (Exception e) {
            log.error("", e);
            return DpUtils.errorJsonMsg("OSS连接异常");
        }
        JSONArray arr = new JSONArray();
        JSONArray errors = new JSONArray();
        JSONArray success = new JSONArray();
        // 构建arr
        JSONObject property = new JSONObject();
        JSONObject relation = new JSONObject();
        JSONObject infosNode = new JSONObject();
        relation.put("link", id);
        if(floorId != null)
            relation.put("floor", floorId);
        arr.add(property);
        property.put("family", family);
        property.put("relation", relation);
        property.put("infos", infosNode);
        JSONObject equipObjInfos = (JSONObject) equipObj.get("infos");
        for(String infoCode : equipObjInfos.keySet())
        {
            if(!infos.get(family).containsKey(infoCode) && !infos.get("eq-gen").containsKey(infoCode)) // 如果信息点不属于该种族或设备通用信息点, 跳过
                continue;
            Object value = equipObjInfos.get(infoCode);
            JSONArray pairs = new JSONArray();
            JSONObject pair = new JSONObject();
            pair.put("value", value);
            pairs.add(pair);
            infosNode.put(infoCode, pairs);
        }
        // -------
        String resultMsg = PropertyUtil.addObj(projectId.substring(2), arr, errors, success, skipErrorInfo, true, null, false);
        if(success.size() > 0)
        {
            JSONObject ret = (JSONObject) success.get(0);
            ret.put("Result", "success");
            ret.put("ResultMsg", "");
            return ret.toJSONString();
        }
        if(errors.size() > 0) {
            String errorMsg = (String) ((JSONObject) errors.get(0)).get("error");
            return DpUtils.errorJsonMsg(errorMsg);
        }
        return DpUtils.errorJsonMsg(resultMsg == null? "" : resultMsg);
    }
    @Path("/project/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String projectQuery(String jsonStr){
        // 查id,
        try{
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/propertyIdQuerySchema.json");
            if(validateInfo != null && validateInfo.length() != 0)
                return  DpUtils.errorJsonMsg(validateInfo);
        }catch (Exception ex)
        {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        try {
            JSONObject query = JSONObject.parseObject(jsonStr);
            //CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);

            JSONArray criteriasNode = (JSONArray) query.get("criterias");
            return PropertyUtil.projectQuery(criteriasNode);
        }catch (Exception ex){
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }
    // 资产修改发送JMS消息的规则
    //	修改所属项目 --> 自身(旧项目id, 新项目id, 资产id), 删除关联岗位(资产id, 项目id)
    //	修改种族 --> 自身(项目id, 资产id, 新种族编码, 旧种族编码) 删除岗位关联(返回资产id, 项目id), 删除信息点(返回项目id, 资产id)
    //	修改信息点 --> 自身(返回资产id, 项目id, 信息点id)
    //	修改关联岗位 --> 自身(资产id, 项目id)
}
