package com.persagy.proxy.dictionary.service.impl;

import cn.hutool.core.collection.CollUtil;
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.basic.model.QueryCriteria;
import com.persagy.dmp.digital.entity.ObjectRelation;
import com.persagy.proxy.adm.request.AdmDictQueryCriteria;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.service.IAdmRelationService;
import com.persagy.proxy.adm.service.impl.AbstractAdmBaseServiceImpl;
import com.persagy.proxy.dictionary.model.AdmDict;
import com.persagy.proxy.dictionary.model.AdmObjectType;
import com.persagy.proxy.dictionary.service.IAdmDictService;
import com.persagy.proxy.object.model.AdmEquipment;
import com.persagy.proxy.dictionary.model.AdmPlanarEquipRequests;
import com.persagy.proxy.object.model.AdmSpace;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.object.service.IAdmEquipmentService;
import com.persagy.proxy.dictionary.service.IAdmPlanarService;
import com.persagy.proxy.object.service.IAdmSpaceService;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
/**
 * @ClassName AdmPlanarServiceImpl
 * @Description: 平面图接口
 * @Author linhuili
 * @Date 2021/9/22 14:17
 * @Version V1.0
 **/
@Service
@Slf4j
public class AdmPlanarServiceImpl extends AbstractAdmBaseServiceImpl<T> implements IAdmPlanarService {

    @Autowired
    private IAdmSpaceService spaceService;

    @Autowired
    private IAdmEquipmentService equipmentService;

    @Autowired
    private IAdmRelationService relationService;

    @Autowired
    private IAdmDictService dictService;

    /**
     * 查询平面图设备信息
     * @param context
     * @param requests
     * @param clazz
     * @return
     * @throws Exception
     */
    @Override
    public AdmResponse queryPlanarEquip(InstanceUrlParam context, AdmPlanarEquipRequests requests, Class<AdmEquipment> clazz) throws Exception {
       AdmResponse admResponse = new AdmResponse();
       if(CollUtil.isEmpty(requests.getZoneTypes()) && CollUtil.isEmpty(requests.getSpaceIds()) && CollUtil.isEmpty(requests.getFuncTypes())){
           //查询建筑楼层下的所有设备（或指定类型下的设备）
          admResponse = queryAdmEquip(context, requests, clazz);
       }else{
           //查询空间下的设备
          admResponse = queryAdmEquipInSpace(context,requests,clazz);
       }
       //结果集处理，设置设备类型名称字段
        List<AdmEquipment> content = (List<AdmEquipment>)admResponse.getContent();
       if(CollUtil.isEmpty(content)){
           return admResponse;
       }
        for (AdmEquipment admEquipment : content) {
            Map<String, String> equipCategory = admEquipment.getEquipCategory();
            if(CollUtil.isEmpty(equipCategory)){
                continue;
            }
            for (Map.Entry<String, String> entry : equipCategory.entrySet()) {
                admEquipment.setCodeName(entry.getValue());
            }
        }
        admResponse.setContent(content);
        return admResponse;
    }

    /**
     * 查询ADM设备信息
     * @param context
     * @param request
     * @param clazz
     * @return
     */
    private AdmResponse queryAdmEquip(InstanceUrlParam context, AdmPlanarEquipRequests request,Class<AdmEquipment> clazz){
        //增加过滤条件
        StringBuilder filters = new StringBuilder();
        filters.append("buildingId = '"+ request.getBuildingId() +"';");
        if(StringUtils.isNotEmpty(request.getFloorId())){
            filters.append("floorId = '"+ request.getFloorId() +"';");
        }
        if(CollUtil.isNotEmpty(request.getEquipTypes())){
            filters.append("classCode in "+"(\'" + java.lang.String.join("\',\'", request.getEquipTypes()) + "\')");
        }
        AdmQueryCriteria equipQueryCriteria = new AdmQueryCriteria();
        equipQueryCriteria.setFilters(filters.toString());
        equipQueryCriteria.setOrders("createTime desc, id desc");

        //级联查询建筑楼层
       /* List<AdmQueryCriteria> cascades = new ArrayList<>();
        AdmQueryCriteria buildCascade = new AdmQueryCriteria();
        buildCascade.setName("building");
        cascades.add(buildCascade);
        AdmQueryCriteria floorCascade = new AdmQueryCriteria();
        floorCascade.setName("floor");
        cascades.add(floorCascade);
        equipQueryCriteria.setCascade(cascades);*/

        log.info(equipQueryCriteria.toString());
        return equipmentService.doQuery(context, equipQueryCriteria, clazz);
    }


    /**
     * 查询ADM设备信息
     * @param context
     * @param request
     * @param clazz
     * @return
     */
    private AdmResponse queryAdmSpace(InstanceUrlParam context, AdmPlanarEquipRequests request,Class<AdmSpace> clazz){
        //增加过滤条件
        StringBuilder filters = new StringBuilder();
        filters.append("buildingId = '"+ request.getBuildingId() +"';");
        if(StringUtils.isNotEmpty(request.getFloorId())){
            filters.append("floorId = '"+ request.getFloorId() +"';");
        }
        if(CollUtil.isNotEmpty(request.getZoneTypes())){
            filters.append("classCode in "+"(\'" + java.lang.String.join("\',\'", request.getZoneTypes()) + "\')");
        }
        if(CollUtil.isNotEmpty(request.getSpaceIds())){
            filters.append("id in "+"(\'" + java.lang.String.join("\',\'", request.getSpaceIds()) + "\')");
        }
        if(CollUtil.isNotEmpty(request.getFuncTypes())){
            filters.append("roomFuncType in "+"(\'" + java.lang.String.join("\',\'", request.getFuncTypes()) + "\')");
        }
        AdmQueryCriteria equipQueryCriteria = new AdmQueryCriteria();
        equipQueryCriteria.setFilters(filters.toString());
        equipQueryCriteria.setOrders("createTime desc, id desc");

        //级联查询建筑楼层-测试用
       /* List<AdmQueryCriteria> cascades = new ArrayList<>();
        AdmQueryCriteria buildCascade = new AdmQueryCriteria();
        buildCascade.setName("building");
        cascades.add(buildCascade);
        AdmQueryCriteria floorCascade = new AdmQueryCriteria();
        floorCascade.setName("floor");
        cascades.add(floorCascade);
        equipQueryCriteria.setCascade(cascades);*/
        log.info(equipQueryCriteria.toString());
        return spaceService.doQuery(context, equipQueryCriteria, clazz);
    }

    /**
     * 查询ADM空间下的设备信息
     * @param context
     * @param requests
     * @param clazz
     * @return
     */
    private AdmResponse queryAdmEquipInSpace(InstanceUrlParam context, AdmPlanarEquipRequests requests,Class<AdmEquipment> clazz){
        //获取空间信息
        /*if(CollUtil.isEmpty(requests.getSpaceIds())){
            //查询建筑/楼层下的空间信息
            spaces = querySpInFl(context, requests, AdmSpace.class);
        }else{
            //根据空间功能类型等过滤空间信息
            spaces = queryDmpSpace(context, requests, AdmSpace.class);
        }*/
        AdmResponse admSpaceResponse = queryAdmSpace(context, requests, AdmSpace.class);
        List<AdmSpace> spaces = (List<AdmSpace>) admSpaceResponse.getContent();
        if(CollUtil.isEmpty(spaces)){
            return AdmResponse.success(new ArrayList<>());
        }
        List<String> spaceIds = spaces.stream().map(k -> k.getId()).collect(Collectors.toList());
        requests.setSpaceIds(spaceIds);
        //查询空间下的设备
        List<AdmEquipment> result = queryEqInSp(context, requests, AdmEquipment.class);
        AdmResponse response = AdmResponse.success(result);
        response.setTotal(result == null ? 0 : Long.valueOf(result.size()));
        return response;
    }
    /**
     * 查询平面图空间
     * @param context
     * @param requests
     * @param clazz
     * @return
     * @throws Exception
     */
    @Override
    public AdmResponse queryPlanarSpace(InstanceUrlParam context, AdmPlanarEquipRequests requests, Class<AdmSpace> clazz) throws Exception {
       /* List<AdmSpace> spaces = new ArrayList<>();
        //获取空间信息
        if(CollUtil.isEmpty(requests.getSpaceIds())){
            //查询建筑/楼层下的空间信息
            spaces = querySpInFl(context, requests, AdmSpace.class);
        }else{
            //根据空间功能类型等过滤空间信息
            spaces = queryDmpSpace(context, requests, AdmSpace.class);
        }*/
        //查询空间类型
        AdmDict dictCriteria = new AdmDict();
        dictCriteria.setType("space");
        AdmResponse dictResponse = dictService.queryCategory(context, dictCriteria,AdmObjectType.class);
        List<AdmObjectType> objectTypeList = (List<AdmObjectType>)dictResponse.getContent();
        Map<String,String> objectTypeMap = new HashMap<>();
        if(CollUtil.isNotEmpty(objectTypeList)){
           objectTypeMap = objectTypeList.stream().collect(Collectors.toMap(AdmObjectType::getCode,AdmObjectType::getName));
        }
        //查询空间信息
        AdmResponse admResponse = queryAdmSpace(context, requests, clazz);

        //结果集处理，设置空间类型名称字段
        List<AdmSpace> content = (List<AdmSpace>)admResponse.getContent();
        if(CollUtil.isEmpty(content)){
            return admResponse;
        }
        for (AdmSpace admSpace : content) {
            if(CollUtil.isEmpty(objectTypeMap)){
                continue;
            }
            if(StringUtils.isNotEmpty(admSpace.getClassCode())){
                admSpace.setCodeName(objectTypeMap.get(admSpace.getClassCode()));
            }
        }
        admResponse.setContent(content);
        return admResponse;
    }

    /**
     * 查询楼层下的空间
     * @param context
     * @param requests
     * @return
     */
    private List<AdmSpace> querySpInFl(InstanceUrlParam context, AdmPlanarEquipRequests requests, Class<AdmSpace> clazz){
        if(CollUtil.isEmpty(requests.getZoneTypes()) && CollUtil.isNotEmpty(requests.getFuncTypes())){
            return new ArrayList<>();
        }

        //设置空间基础查询条件
        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
        if(CollUtil.isNotEmpty(requests.getZoneTypes())){
            ArrayNode array = criteria.putObject("classCode").putArray("$in");
            requests.getZoneTypes().forEach(code -> array.add(code));
        }

        if(CollUtil.isNotEmpty(requests.getFuncTypes())){
            ArrayNode array = criteria.putObject("roomFuncType").putArray("$in");
            requests.getFuncTypes().forEach(code -> array.add(code));
        }
        //设置空间关系查询条件
        QueryCriteria dmpRequest = new QueryCriteria();
        if(StringUtils.isEmpty(requests.getFloorId())){
            dmpRequest = transDmpRelationCriteria(criteria,"ArchSubset", "Bd2Sp", requests.getBuildingId(), 0);
        }else{
            dmpRequest = transDmpRelationCriteria(criteria,"ArchSubset", "Fl2Sp", requests.getFloorId(), 0);
        }

        //查询物理世界空间信息
        AdmResponse response = spaceService.doQuery(context, dmpRequest, clazz);
        return (List<AdmSpace>)response.getContent();
    }

    /**
     * 查询空间下的设备
     * @param context
     * @param requests
     * @param clazz
     * @return
     */
    private List<AdmEquipment> queryEqInSp(InstanceUrlParam context,AdmPlanarEquipRequests requests,Class<AdmEquipment> clazz){
        List<String> spaceIds = requests.getSpaceIds();
        if(CollUtil.isEmpty(spaceIds)){
            return new ArrayList<>();
        }
        //查询关系数据
        QueryCriteria queryCriteria = new QueryCriteria();
        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
        criteria.put("graphCode","MechInArch");
        criteria.put("relCode","Eq2Sp");
        ArrayNode objNode = criteria.putArray("objTo");
        spaceIds.forEach(id -> objNode.add(id));
        queryCriteria.setCriteria(criteria);
        List<ObjectRelation> relationList = relationService.queryByCondition(context, queryCriteria);
        Set<String> equipIds = relationList.stream().map(ObjectRelation::getObjFrom).collect(Collectors.toSet());
        if(CollUtil.isEmpty(equipIds)){
            return new ArrayList<>();
        }
        //查询设备信息
        StringBuilder filters = new StringBuilder();
        if(CollUtil.isNotEmpty(requests.getEquipTypes())){
            filters.append("classCode in "+"(\'" + java.lang.String.join("\',\'", requests.getEquipTypes()) + "\')");
        }
        if(CollUtil.isNotEmpty(equipIds)){
            filters.append("id in "+"(\'" + java.lang.String.join("\',\'", equipIds) + "\')");
        }
        AdmQueryCriteria equipQueryCriteria = new AdmQueryCriteria();
        equipQueryCriteria.setFilters(filters.toString());
        equipQueryCriteria.setOrders("createTime desc, id desc");

        AdmResponse admResponse = equipmentService.doQuery(context, equipQueryCriteria, clazz);

        return (List<AdmEquipment>) admResponse.getContent();
    }

    /**
     * 查询中台空间信息
     * @param context
     * @param requests
     * @return
     */
    private List<AdmSpace> queryDmpSpace(InstanceUrlParam context, AdmPlanarEquipRequests requests, Class<AdmSpace> clazz){
        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
        if(CollUtil.isNotEmpty(requests.getSpaceIds())){
            ArrayNode array = criteria.putObject("id").putArray("$in");
            requests.getZoneTypes().forEach(code -> array.add(code));
        }
        if(CollUtil.isNotEmpty(requests.getFuncTypes())){
            ArrayNode array = criteria.putObject("roomFuncType").putArray("$in");
            requests.getFuncTypes().forEach(code -> array.add(code));
        }
        if(CollUtil.isNotEmpty(requests.getZoneTypes())){
            ArrayNode array = criteria.putObject("objType").putArray("$in");
            requests.getZoneTypes().forEach(code -> array.add(code));
        }
        QueryCriteria dmpRequest = new QueryCriteria();
        dmpRequest.setCriteria(criteria);

        //查询物理世界空间信息
        AdmResponse response = spaceService.doQuery(context, dmpRequest, clazz);
        return (List<AdmSpace>)response.getContent();
    }

    /**
     * 获取关系查询条件
     * @param graphCode
     * @param relCode
     * @param id （fromID/targetID）
     * @param direct  0 正向 1反向
     * @return
     */
    public static QueryCriteria transDmpRelationCriteria(ObjectNode objectNode,String graphCode, String relCode, String id, Integer direct){
        QueryCriteria queryCriteria = new QueryCriteria();

        ObjectNode object = JsonNodeFactory.instance.objectNode();
        object.put("graphCode", graphCode);
        object.put("relCode", relCode);
        if(direct == 0){
            //正向查询 objFrom->objTo
            object.put("objFrom", id);
            objectNode.put("relationTo",object);
        }else{
            //反向查询 objTo->objFrom
            object.put("objTo", id);
            objectNode.put("relationFrom",object);
        }
        queryCriteria.setCriteria(objectNode);
        return queryCriteria;
    }

}
