package com.persagy.proxy.object.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
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.dto.RequestData;
import com.persagy.dmp.basic.model.QueryCriteria;
import com.persagy.dmp.basic.utils.JsonNodeUtils;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.common.model.entity.BaseEntity;
import com.persagy.dmp.define.client.DigitalObjectInfoFacade;
import com.persagy.dmp.define.entity.ObjectInfoDefine;
import com.persagy.dmp.digital.client.DigitalObjectFacade;
import com.persagy.dmp.digital.client.DigitalRelationFacade;
import com.persagy.dmp.simple.client.DigitalObjectSimpleFacade;
import com.persagy.proxy.adm.request.AdmCreateRequest;
import com.persagy.proxy.adm.request.AdmCreateResponse;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.service.IAdmRelationService;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.adm.utils.AdmQueryCriteriaHelper;
import com.persagy.proxy.adm.utils.ObjectNameUtil;
import com.persagy.proxy.common.entity.RelationDTO;
import com.persagy.proxy.object.model.*;
import com.persagy.proxy.object.service.IAdmBuildingService;
import com.persagy.proxy.object.service.IAdmShaftService;
import com.persagy.proxy.object.service.IAdmSpaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.ws.rs.QueryParam;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Adm 竖井 API
 * @author lvxy
 * @date 2021/8/16
 */

@RestController
@RequestMapping("/object/shaft")
public class AdmShaftController {
    @Autowired
    private IAdmShaftService service;
    @Autowired
    private IAdmRelationService relationService;
    @Autowired
    private IAdmBuildingService buildingService;
    @Autowired
    private IAdmSpaceService spaceService;

    /**
     * 统计
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/count")
    public AdmResponse count(@RequestBody AdmQueryCriteria request) throws Exception {
        request.setName("shaft");
        request.setOnlyCount(true);
        return service.doQuery(AdmContextUtil.toDmpContext(), request, AdmShaft.class);
    }

    /**
     * 创建
     * @param createRequest
     * @return
     * @throws Exception
     */
    @PostMapping("/create")
    public AdmCreateResponse create(@RequestBody AdmCreateRequest<AdmShaft> createRequest) throws Exception {
        List<AdmShaft> vos = CollUtil.newArrayList(createRequest.getContent());
        List<AdmShaft> unRelationShaft = new ArrayList<>();
        List<AdmShaft> admShafts = new ArrayList<>(vos.size());
        List<RelationDTO> relationDTOS = new ArrayList<>(vos.size());
        vos.stream().forEach(admShaft -> {
            if (StrUtil.isEmpty(admShaft.getName())) {
                admShaft.setName(ObjectNameUtil.objectName("竖井-"));
            }
            if(CollUtil.isEmpty(admShaft.getBuildingList())){
                unRelationShaft.add(admShaft);
            }else{
                //插入对象 添加关系
                List<AdmShaft> shafts = service.doInsert(AdmContextUtil.toDmpContext(), AdmShaft.class, CollUtil.newArrayList(admShaft));
                admShaft.getBuildingList().stream().forEach(admBuilding ->{
                    if(StrUtil.isNotEmpty(admBuilding.getId())){
                        relationDTOS.add(new RelationDTO(null, "ArchSubset", "Bd2Sh", null , admBuilding.getId(), shafts.get(0).getId()));
                    }
                });
                admShafts.addAll(shafts);
            }
        });
        if(CollUtil.isNotEmpty(relationDTOS)){
            relationService.doSave(AdmContextUtil.toDmpContext(), relationDTOS);
        }
        if(CollUtil.isNotEmpty(unRelationShaft)){
            List shaftList = service.doInsert(AdmContextUtil.toDmpContext(), AdmShaft.class, unRelationShaft);
            admShafts.addAll(shaftList);
        }
        return AdmCreateResponse.success(admShafts);
    }

    /**
     * 根据ID删除
     * @param vos
     * @return
     * @throws Exception
     */
    @PostMapping("/delete")
    public AdmResponse delete( @RequestBody List<AdmShaft> vos) throws Exception {       
        service.doDelete(AdmContextUtil.toDmpContext(), vos);
        return AdmResponse.success();
    }

    /**
     * 更新
     * @param createRequest
     * @return
     * @throws Exception
     */
    @PostMapping("/update")
    public AdmResponse update(@RequestBody AdmCreateRequest<AdmShaft> createRequest) throws Exception {
        List<AdmShaft> vos = CollUtil.newArrayList(createRequest.getContent());
        vos = service.doUpdate(AdmContextUtil.toDmpContext(), AdmShaft.class, vos);
        return AdmResponse.success(vos);
    }

    /**
     * 查询
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/query")
    public AdmResponse query(@RequestBody AdmQueryCriteria request) throws Exception {      
        request.setName(AdmShaft.OBJ_TYPE);
        return service.doQuery(AdmContextUtil.toDmpContext(), request, AdmShaft.class);
    }

    /**
     * 查询竖井信息-包含统计信息
     * 此方法可能会弃用
     *
     * 暂不实现
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/query-with-count")
    public AdmResponse queryWithCount(@RequestBody AdmQueryCriteria request) throws Exception {       
        request.setName("shaft");
        return service.doQuery(AdmContextUtil.toDmpContext(), request, AdmShaft.class);
    }

    /**
     * 查询关联元空间
     * 可能移至关系
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/relate-space")
    public AdmResponse queryRelateSp(@RequestBody JSONObject request) throws Exception {      
        //Sh2Sp
        // 先取消后重新建立
        if(JSONUtil.isNull(request)){
            return AdmResponse.failure("参数为空");
        }
        String shaftId = request.getString("shaftId");
        String spaceId = request.getString("spaceId");
        // 组装条件
        QueryCriteria criteria = new QueryCriteria();
        if(!StrUtil.isAllNotEmpty(shaftId,spaceId)) {
            return AdmResponse.failure("必填项：shaftId（竖井id）、spaceId(空间id)");
        }
        ObjectNode node = JsonNodeFactory.instance.objectNode();
        node.put("graphCode", "ArchSubset");
        node.put("relCode", "Sh2Sp");
        node.put("objFrom", shaftId);
        criteria.setCriteria(node);
        relationService.doDelete(AdmContextUtil.toDmpContext(), criteria);

        List<String> spaceIds = Arrays.asList(spaceId.split(","));
        Set<String> existsIds = spaceExists(spaceIds);
        List<String> failureList = null;
        if(CollUtil.isNotEmpty(existsIds)){
            failureList = spaceIds.stream().filter(isId -> !existsIds.contains(isId)).collect(Collectors.toList());
            List<RelationDTO> relationDTOS = new ArrayList<>();
            existsIds.stream().forEach(spId -> {
                RelationDTO relationDTO = new RelationDTO();
                relationDTO.setGraphCode("ArchSubset");
                relationDTO.setObjFrom(shaftId);
                relationDTO.setRelCode("Sh2Sp");
                relationDTO.setObjTo(spId);
                relationDTOS.add(relationDTO);
            });
            List<ObjectNode> nodeList = JsonNodeUtils.toListNode(relationDTOS, null, null);
            DigitalRelationFacade.create(AdmContextUtil.toDmpContext().getGroupCode(), AdmContextUtil.toDmpContext().getProjectId(),AdmContextUtil.toDmpContext().getAppId(), null, nodeList);
        }else{
            failureList = spaceIds;
        }

        if(CollUtil.isNotEmpty(failureList))
            return AdmResponse.failure("元空间 " +failureList.stream().collect(Collectors.joining(","))+ " 不存在");
        else
            return AdmResponse.success();
    }

    /**
     * 查询项目下已有的竖井类型
     * 此方法可能会弃用
     * {
     *     "id":"shaftFuncType",
     *     "name":"竖井功能"
     * }
     * 
     * @return
     * @throws Exception
     */
    @PostMapping("/query-shaft-functype")
    public AdmResponse queryShFuncType() throws Exception {
        String projectId = AdmContextUtil.toDmpContext().getProjectId();
        if(StrUtil.isNotEmpty(projectId)){
            AdmResponse admResponse = AdmResponse.success();
            //查询参数请求查询的类型是否存在
            AdmQueryCriteria admQueryCriteria = new AdmQueryCriteria();
            StringBuilder filters = new StringBuilder(" code = '");
            filters.append("shaftFuncType").append("';");
            filters.append(" classCode ='").append("shaft").append(" '");
            admQueryCriteria.setFilters(filters.toString());
            QueryCriteria dmpRequest = AdmQueryCriteriaHelper.toDmpCriteria(admQueryCriteria);
            List<ObjectInfoDefine> defineList = DigitalObjectInfoFacade.query(AdmContextUtil.toDmpContext().getGroupCode(),AdmContextUtil.toDmpContext().getProjectId(),AdmContextUtil.toDmpContext().getAppId(),null,dmpRequest);
            //是否有该类型的竖井信息
            if(CollUtil.isNotEmpty(defineList)){
                //查询中台项目实际使用该信息点的竖井
                RequestData requestData = new RequestData();
                requestData.setObjType(AdmShaft.OBJ_TYPE);
                requestData.setGroups(Arrays.asList("shaftFuncType"));
                List<Map<String, Object>> listInfos = DigitalObjectSimpleFacade.queryObjectCountByObjInfos(AdmContextUtil.toDmpContext().getGroupCode(),AdmContextUtil.toDmpContext().getAppId(),null, requestData);

                if(CollUtil.isNotEmpty(listInfos)){
                    ArrayNode datasource = defineList.get(0).getDataSource();
                    List<HashMap> datasourceList = JSONUtil.toList(datasource.toString(), HashMap.class);
                    Map<String, String> datasourceMap = new HashMap<>(datasourceList.size());
                    for (HashMap map : datasourceList){
                        datasourceMap.put(map.get("code").toString(),map.get("name").toString());
                    }
                    Map<String, Object> datasourceMapUsed = new HashMap<>(datasourceMap.size());
                    listInfos.stream().forEach(map -> {
                        if(!datasourceMapUsed.containsKey(map.get("shaftFuncType")) || datasourceMap.containsKey(map.get("shaftFuncType"))){
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("id", map.get("shaftFuncType").toString());
                            jsonObject.put("name", datasourceMap.get(map.get("shaftFuncType").toString()));
                            datasourceMapUsed.put(map.get("shaftFuncType").toString(),jsonObject);
                        }
                    });
                    if(CollUtil.isNotEmpty(datasourceMapUsed)){
                        admResponse = AdmResponse.success(datasourceMapUsed.values().stream().collect(Collectors.toList()));
                    }
                }
            }
            return admResponse;
        }else{
            return AdmResponse.failure("项目Id为空");
        }
    }

    /**
     * 查询和当前竖井有关联的业务空间
     * shaftId 为竖井id
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/shaft-zoneSpaceBaseTable")
    public AdmResponse queryZoneSp(@RequestParam("ShaftId") String ShaftId, @RequestBody AdmQueryCriteria request) throws Exception {
        // 组装条件
        request.setName(AdmSpace.OBJ_TYPE);
        QueryCriteria queryCriteria = AdmQueryCriteriaHelper.toDmpCriteria(request);
        if(!StrUtil.isNotEmpty(ShaftId)) {
            return AdmResponse.failure("必填项：shaftId（竖井id）");
        }
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        ObjectNode criteria = queryCriteria.getCriteria();
        if (null==criteria){
            criteria = objectMapper.createObjectNode();
        }
        ObjectNode relationTO = JsonNodeFactory.instance.objectNode();
        relationTO.put("relCode", "Sh2Sp");
        relationTO.put("graphCode","ArchSubset");
        relationTO.put("objFrom", ShaftId);
        criteria.putPOJO("relationTo", relationTO);
        queryCriteria.setCriteria(criteria);

        AdmResponse admResponse = spaceService.doQuery(AdmContextUtil.toDmpContext(), queryCriteria, AdmSpace.class);
        return admResponse;
    }

    /**
     * 查询和当前竖井有关联的业务空间所在建筑及楼层信息
     * shaftId 为竖井id
     * 
     * @return
     * @throws Exception
     */
    @GetMapping("/shaft-zoneSpaceBaseTable-building")
    public AdmResponse queryZoneSpBd(@RequestParam("shaftId") String shaftId,
                                     @RequestParam(value = "objectType",required = false) String objectType) throws Exception {
        if(!StrUtil.isAllNotEmpty(shaftId,AdmContextUtil.toDmpContext().getProjectId())) {
            return AdmResponse.failure("必填项：shaftId（竖井id）、projectId(项目id)");
        }
        // 组装条件 查询竖井下的空间
        AdmQueryCriteria admQueryCriteriaSpace = new AdmQueryCriteria();
        admQueryCriteriaSpace.setName(AdmSpace.OBJ_TYPE);
        if(StrUtil.isNotEmpty(objectType)){
            admQueryCriteriaSpace.setFilters(" classCode = '"+objectType+"'");
        }
        ObjectNode relationTO = JsonNodeFactory.instance.objectNode();
        relationTO.put("relCode", "Sh2Sp");
        relationTO.put("graphCode","ArchSubset");
        relationTO.put("objFrom", shaftId);
        relationTO.put("relValue", objectType);
        admQueryCriteriaSpace.setRelationTo(relationTO);

        //1 空间级联建筑
        List<AdmQueryCriteria> cascadeSp2BdFl = new ArrayList<>(1);
        //1.1 空间级联楼层
        AdmQueryCriteria cascadeSpFl = new AdmQueryCriteria();
        cascadeSpFl.setName("floorList");
        cascadeSpFl.setProjection(Arrays.asList("id","name","localName","floorSequenceID"));
        cascadeSpFl.setOrders("floorSequenceId desc");
        cascadeSp2BdFl.add(cascadeSpFl);

        //1.2 空间级联建
        AdmQueryCriteria queryCriteriaBd = new AdmQueryCriteria();
        queryCriteriaBd.setName("building");
        queryCriteriaBd.setProjection(Arrays.asList("id","name","localName","floor"));

        cascadeSp2BdFl.add(queryCriteriaBd);
        admQueryCriteriaSpace.setCascade(cascadeSp2BdFl);

        AdmResponse admResponseSp = spaceService.query(admQueryCriteriaSpace);
        if (CollUtil.isEmpty(admResponseSp.getContent())){
            return AdmResponse.success();
        }
        //处理建筑下的楼层不是和空间关联的信息
        List<AdmSpace> spaces = (List<AdmSpace>) admResponseSp.getContent();
        List<AdmBuilding> admBuildingList = new ArrayList<>();
        Map<String,List<AdmFloor>> buildingMap = new HashMap<>();
        Set<String> floorIds = new HashSet<>();
        for(AdmSpace space : spaces){
            AdmBuilding building = space.getBuilding();
            List<AdmFloor> floorList = space.getFloorList();
            if(null == building){
                continue;
            }
            List<AdmFloor> floors = buildingMap.getOrDefault(building.getId(), new ArrayList<>());
            if(CollUtil.isNotEmpty(floorList)){
                for (AdmFloor admFloor : floorList) {
                    if (floorIds.contains(admFloor.getId())){
                        continue;
                    }
                    floors.add(admFloor);
                    floorIds.add(admFloor.getId());
                }
            }
            if (buildingMap.containsKey(building.getId())){
                continue;
            }
            buildingMap.put(building.getId(),floors);
            admBuildingList.add(building);
        }
        for (AdmBuilding building : admBuildingList) {
            List<AdmFloor> floors = buildingMap.getOrDefault(building.getId(), new ArrayList<>());
            building.setFloor(floors.stream()
                    .sorted((f1,f2)-> CompareUtil.compare(f2.getFloorSequenceID(),f1.getFloorSequenceID(),false))
                    .collect(Collectors.toList()));
        }
        return AdmResponse.success(admBuildingList);
    }

    /*@GetMapping("/shaft-zoneSpaceBaseTable-building")
    public AdmResponse queryZoneSpBd(@QueryParam("shaftId") String shaftId,
             @QueryParam("objectType") String objectType) throws Exception {
        if(!StrUtil.isAllNotEmpty(shaftId,AdmContextUtil.toDmpContext().getProjectId())) {
            return AdmResponse.failure("必填项：shaftId（竖井id）、projectId(项目id)");
        }
        // 组装条件 查询竖井下的空间
        AdmQueryCriteria admQueryCriteria = new AdmQueryCriteria();
        admQueryCriteria.setName(AdmSpace.OBJ_TYPE);
        if(StrUtil.isNotEmpty(objectType)){
            admQueryCriteria.setFilters(" classCode = '"+objectType+"'");
        }
        //转化为中台的查询条件
        QueryCriteria queryCriteria = AdmQueryCriteriaHelper.toDmpCriteria(admQueryCriteria);

        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
        ObjectNode relationTO = JsonNodeFactory.instance.objectNode();
        relationTO.put("relCode", "Sh2Sp");
        relationTO.put("graphCode","ArchSubset");
        relationTO.put("objFrom", shaftId);
        criteria.putPOJO("relationTo", relationTO);
        criteria.put("objType", AdmSpace.OBJ_TYPE);
        queryCriteria.setCriteria(criteria);

        List<ObjectNode> spaceList = DigitalObjectFacade.query(AdmContextUtil.toDmpContext().getGroupCode(), AdmContextUtil.toDmpContext().getProjectId(), AdmContextUtil.toDmpContext().getAppId(), null, queryCriteria);
        if(CollUtil.isNotEmpty(spaceList)){
            AdmQueryCriteria queryCriteriaBd = new AdmQueryCriteria();
            queryCriteriaBd.setName(AdmBuilding.OBJ_TYPE);
            queryCriteriaBd.setProjection(Arrays.asList("id","name","localName","floor"));
            //建筑级联楼层
            List<AdmQueryCriteria> cascade = new ArrayList<>(1);
            AdmQueryCriteria cascadeFloor = new AdmQueryCriteria();
            cascadeFloor.setName(AdmFloor.OBJ_TYPE);
            cascadeFloor.setProjection(Arrays.asList("id","name","localName"));
            cascade.add(cascadeFloor);
            cascadeFloor.setOrders("floorSequenceId desc");
            queryCriteriaBd.setCascade(cascade);

            List<AdmSpace> vos = JSONUtil.toList(spaceList.toString(), AdmSpace.class);
            Map<String, AdmSpace> admSpaceMap = CollUtil.fieldValueMap(vos, "buildingId");
            ObjectNode relationFrom = JsonNodeFactory.instance.objectNode();
            relationFrom.put("relCode", "Bd2Sp");
            relationFrom.put("graphCode","ArchSubset");
            ArrayNode arrayNode = relationFrom.putObject("objTo").putArray("$in");
            admSpaceMap.keySet().stream().forEach(spaceId -> arrayNode.add(spaceId));
            AdmResponse response =  buildingService.doQuery(AdmContextUtil.toDmpContext(), queryCriteriaBd, AdmBuilding.class);
            return response;
        }else{
            return AdmResponse.success();
        }
    }
*/
    /**
     * 查询和当前竖井没有关联的业务空间
     * shaftId 为竖井id
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/un-shaft-zoneSpaceBaseTable")
    public AdmResponse queryUnZoneSp(@QueryParam("shaftId") String shaftId,
                             @RequestBody AdmQueryCriteria request) throws Exception {
        // 组装条件
        if(!StrUtil.isNotEmpty(shaftId)) {
            return AdmResponse.failure("必填项：shaftId（竖井id）");
        }
        request.setName(AdmSpace.OBJ_TYPE);
        request.resetRelationCond(false, "ArchSubset", "Sh2Sp", AdmSpace.OBJ_TYPE, shaftId, false);
        QueryCriteria queryCriteria = AdmQueryCriteriaHelper.toDmpCriteria(request);
        List<ObjectNode> spaceList = DigitalObjectFacade.query(AdmContextUtil.toDmpContext().getGroupCode(), AdmContextUtil.toDmpContext().getProjectId(), AdmContextUtil.toDmpContext().getAppId(), null, queryCriteria);
        if(CollUtil.isNotEmpty(spaceList)){
            List<AdmSpace> vos = JSONUtil.toList(spaceList.toString(), AdmSpace.class);
            return AdmResponse.success(spaceList, request);
        }else{
            return AdmResponse.success();
        }
    }

    /**
     * 元空间是否存在
     *
     * @param       spaceIds       failureList
     * @return      是否存在
     */
    private Set<String> spaceExists(List<String> spaceIds) {
        QueryCriteria queryCriteria = new QueryCriteria();
        ObjectNode node = JsonNodeFactory.instance.objectNode();
        ArrayNode arrayNode = node.putObject("id").putArray("$in");
        spaceIds.stream().forEach(spaceId -> arrayNode.add(spaceId));
        node.put("objType","ispace");
        queryCriteria.setCriteria(node);
        List<ObjectNode> ispaces = DigitalObjectFacade.query(AdmContextUtil.toDmpContext().getGroupCode(),AdmContextUtil.toDmpContext().getProjectId(),AdmContextUtil.toDmpContext().getAppId(),AdmContextUtil.toDmpContext().getAppId(),queryCriteria);
        if(CollUtil.isNotEmpty(ispaces)){
            List<AdmISpace> iSpaceList = JSONUtil.toList(JSONUtil.parseArray(ispaces.toString()), AdmISpace.class);
            Map<String, AdmISpace> admISpaceMap = CollUtil.fieldValueMap(iSpaceList, BaseEntity.PROP_ID);
            return admISpaceMap.keySet();
        }else{
            return null;
        }
    }

}
