package com.persagy.proxy.relation.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
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.common.context.AppContext;
import com.persagy.dmp.define.entity.ObjectTypeDefine;
import com.persagy.dmp.digital.client.DigitalObjectFacade;
import com.persagy.dmp.digital.client.DigitalRelationFacade;
import com.persagy.dmp.digital.entity.ObjectDigital;
import com.persagy.dmp.digital.entity.ObjectRelation;
import com.persagy.proxy.adm.constant.AdmCommonConstant;
import com.persagy.proxy.adm.constant.AdmDictCategoryEnum;
import com.persagy.proxy.adm.constant.AdmObjectType;
import com.persagy.proxy.adm.constant.AdmRelationTypeEnum;
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.common.client.DmpRwdClient;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.common.entity.RelationDTO;
import com.persagy.proxy.report.service.IRelationReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @description:023、关系-竖井下的业务空间
 * @author:lgy
 * @data:2021/9/13 14:49
 */
@RestController
@RequestMapping("/rel/sh-contain-sp-base")
public class RelationShContainSpBaseController {

    @Autowired
    private IAdmRelationService service;
    
    @Autowired
    DmpRwdClient rwdClient;
    
    @Autowired
    private IRelationReportService relationReportService;

    /**
     * 默认图类型
     */
    public static String DEFAULT_GRAPH_CODE = "ArchSubset";
    /**
     * 默认边类型
     */
    public static String DEFAULT_REL_CODE = "Sh2Sp";

    /**
     * 创建竖井下的业务空间关系
     * @param param 竖井和业务空间的关系对象
     * @return
     * @throws Exception
     */
    @PostMapping(value = {"/link"})
    public AdmResponse create(@RequestBody JSONObject param) throws Exception {
        String shaftId = param.getString("shaftId");
        String spaceId = param.getString("spaceId");
        String type = param.getString("objectType");
        if(!StrUtil.isAllNotEmpty(shaftId,spaceId)) {
            return AdmResponse.failure("必填项：ShaftID（竖井id）、SpaceID(业务空间id)");
        }
        // 创建关系对象
        List<RelationDTO> voList = new ArrayList<>();
        voList.add(new RelationDTO(null, DEFAULT_GRAPH_CODE, DEFAULT_REL_CODE, type, shaftId , spaceId));
        service.doSave(AdmContextUtil.toDmpContext(), voList);
        return AdmResponse.success();
    }

    /**
     * 根据对象删除关系
     *根据对象删除竖井下的业务空间关系，只针对一个对象
     * @param    param    对象
     * @param   type                 空间类型
     * @return                       删除的结果信息
     */
    @PostMapping("/unlink")
    public AdmResponse delete(@RequestParam(value = "type", required = false) String type,
                              @RequestBody List<JSONObject> param) throws Exception {
        if(CollUtil.isEmpty(param)) {
            return AdmResponse.success();
        }
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        // 组装条件
        QueryCriteria criteria = new QueryCriteria();
        String shaftId = param.get(0).getString("shaftId");
        String spaceId = param.get(0).getString("spaceId");
        if(!StrUtil.isAllNotEmpty(shaftId,spaceId)) {
            return AdmResponse.failure("必填项：ShaftID（竖井id）、SpaceID(业务空间id)");
        }
        ObjectNode node = JsonNodeFactory.instance.objectNode();
        node.put("graphCode", DEFAULT_GRAPH_CODE);
        node.put("relCode", DEFAULT_REL_CODE);
        node.put("relValue", type);
        node.put("objFrom", shaftId);
        node.put("objTo",spaceId);
        criteria.setCriteria(node);
        service.doDelete(context, criteria);
        return AdmResponse.success();
    }

    /**
     * 创建竖井下的业务空间关系
     *
     * @param   param     竖井和业务空间的关系对象
     * @param   type                 空间类型
     * @return                       创建的结果信息
     */
    @PostMapping("/link-shsps")
    public AdmResponse createShsps(@RequestParam(value = "type", required = false) String type,
                                @RequestBody JSONObject param) {
        String shaftId = param.getString("shaftId");
        JSONArray spaceIdList = param.getJSONArray("spaceIdList");
        if(StrUtil.isBlank(shaftId) || CollUtil.isEmpty(spaceIdList)) {
            return AdmResponse.success("空间类型和空间列表不能为空");
        }
        // 创建关系对象.先删除，后添加
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        List<RelationDTO> voList = new ArrayList<>();
        for(int i = 0;i < spaceIdList.size();i++) {
            String spaceId = spaceIdList.getString(i);
            if(StrUtil.isBlank(spaceId)) {
                continue;
            }
            QueryCriteria queryRequest = new QueryCriteria();
            ObjectNode node = JsonNodeFactory.instance.objectNode();
            node.put("graphCode", DEFAULT_GRAPH_CODE);
            node.put("relCode", DEFAULT_REL_CODE);
            node.put("relValue", type);
            node.put("objFrom", shaftId);
            node.put("objTo", spaceId);
            queryRequest.setCriteria(node);
            service.doDelete(context,queryRequest);
            // 创建关系对象 - 参考(datasyn中DataCenterSync.kt)
            voList.add(new RelationDTO(null, DEFAULT_GRAPH_CODE, DEFAULT_REL_CODE, type, shaftId, spaceId));
        }
        // 组装上下文条件
        service.doSave(context, voList);
        return AdmResponse.success();
    }

    /**
     * 竖井下的业务空间，空间一对多
     * @param   param     竖井和业务空间的关系对象
     * @param   type                 空间类型
     * @return                       创建的结果信息
     */
    @PostMapping("/link-spshs")
    public AdmResponse createSpshs(@RequestParam(value = "type", required = false) String type,
                                   @RequestBody JSONObject param) {
        String spaceId = param.getString("spaceId");
        JSONArray shaftIdList = param.getJSONArray("shaftIdList");
        if(StrUtil.isBlank(spaceId) || CollUtil.isEmpty(shaftIdList)) {
            return AdmResponse.failure("必填项：SpaceId（业务空间id）、ShaftIDList(竖井id列表)");
        }
        // 创建关系对象.先删除，后添加
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        List<RelationDTO> voList = new ArrayList<>();
        for(int i = 0;i < shaftIdList.size();i++) {
            String shaftId = shaftIdList.getString(i);
            if(StrUtil.isBlank(shaftId)) {
                continue;
            }
            QueryCriteria queryRequest = new QueryCriteria();
            ObjectNode node = JsonNodeFactory.instance.objectNode();
            node.put("graphCode", DEFAULT_GRAPH_CODE);
            node.put("relCode", DEFAULT_REL_CODE);
            node.put("relValue", type);
            node.put("objFrom", shaftId);
            node.put("objTo", spaceId);
            queryRequest.setCriteria(node);
            service.doDelete(context,queryRequest);
            // 创建关系对象 - 参考(datasyn中DataCenterSync.kt)
            voList.add(new RelationDTO(null, DEFAULT_GRAPH_CODE, DEFAULT_REL_CODE, type, shaftId, spaceId));
        }
        // 组装上下文条件
        service.doSave(context, voList);
        return AdmResponse.success();
    }

    /**
     * 创建竖井下的业务空间，竖井一对多，此方法会覆盖以前的记录
     *
     * @param   param     竖井和业务空间的关系对象
     * @param   type                 空间类型
     * @return                       创建的结果信息
     */
    @PostMapping("/link-shsps-replace")
    public AdmResponse createShSpsReplace(@RequestParam(value = "Type", required = false) String type,
                                   @RequestParam(value = "BuildingId", required = false) String buildingId,
                                   @RequestParam(value = "FloorId", required = false) String floorId,
                                   @RequestBody JSONObject param) throws Exception {
        String shaftId = param.getString("shaftId");
        JSONArray spaceIdList = param.getJSONArray("spaceIdList");

        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        
        // 查出和当前竖井关联并为当前空间类型的的业务空间id
        QueryCriteria queryRequestTmp = new QueryCriteria();
        ObjectNode nodeTmp = JsonNodeFactory.instance.objectNode();
        nodeTmp.put("graphCode", DEFAULT_GRAPH_CODE);
        nodeTmp.put("relCode", DEFAULT_REL_CODE);
        nodeTmp.put("relValue", type);
        nodeTmp.put("objFrom", shaftId);
        queryRequestTmp.setCriteria(nodeTmp);
        Set<String> oldSpaceIds = service.queryByCondition(context, queryRequestTmp).stream().map(ObjectRelation::getObjTo).collect(Collectors.toSet());
        
        // 楼层、建筑、对象类查询的空间id
        RequestData requestData = RequestData.builder().buildingId(buildingId).classCode(type)
                .floorId(floorId).projectId(context.getProjectId()).objType(AdmDictCategoryEnum.SPACE.getValue()).build();
        List<ObjectDigital> objectDigitals = DigitalObjectFacade.queryObjectListSuperiorId(context.getGroupCode(),
                context.getProjectId(), AdmCommonConstant.APP_ID, context.getUserId(), requestData);
        Set<String> spaceIdSet = objectDigitals.stream().map(ObjectDigital::getId).collect(Collectors.toSet());
        
        //空间id取交集
        if(ObjectUtil.isNotEmpty(oldSpaceIds)){
            spaceIdSet.retainAll(oldSpaceIds);
        }
        //删除空间关系
        for (String oldSpaceId : spaceIdSet) {
            QueryCriteria queryRequest = new QueryCriteria();
            ObjectNode node = JsonNodeFactory.instance.objectNode();
            node.put("graphCode", DEFAULT_GRAPH_CODE);
            node.put("relCode", DEFAULT_REL_CODE);
            node.put("relValue", type);
            node.put("objFrom", shaftId);
            node.put("objTo", oldSpaceId);
            queryRequest.setCriteria(node);
            service.doDelete(context,queryRequest);
        }
        //替换空间关系
        if (CollectionUtil.isNotEmpty(spaceIdList)) {
        	 List<RelationDTO> voList = new ArrayList<>();
             for(int i = 0;i < spaceIdList.size();i++) {
                 String spaceId = spaceIdList.getString(i);
                 if(StrUtil.isBlank(spaceId)) {
                     continue;
                 }
                 QueryCriteria queryRequest = new QueryCriteria();
                 ObjectNode node = JsonNodeFactory.instance.objectNode();
                 node.put("graphCode", DEFAULT_GRAPH_CODE);
                 node.put("relCode", DEFAULT_REL_CODE);
                 node.put("relValue", type);
                 node.put("objFrom", shaftId);
                 node.put("objTo", spaceId);
                 queryRequest.setCriteria(node);
                 service.doDelete(context,queryRequest);
                 // 创建关系对象 - 参考(datasyn中DataCenterSync.kt)
                 voList.add(new RelationDTO(null, DEFAULT_GRAPH_CODE, DEFAULT_REL_CODE, type, shaftId, spaceId));
             }
             // 组装上下文条件
             service.doSave(context, voList);
		}
        return AdmResponse.success();
    }

    /**
     * 查询空间类型和名称
     * @param shaftId shaftId 竖井id
     * @param param param
     * @return {@link AdmResponse}
     * @author lgy
     * @date 2021/9/23 18:37
     */
    @PostMapping("/space-type-query")
    public AdmResponse spaceTypeQuery(@RequestParam(value = "shaftId", required = false) String shaftId,
                              @RequestBody JSONObject param) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        if (StrUtil.isBlank(shaftId)) {
        	shaftId = param.getString("shaftId");
		}
        String groupCode = AppContext.getContext().getGroupCode();
		String projectId = AppContext.getContext().getProjectId();
		
        List<ObjectTypeDefine> classList = this.relationReportService.queryClassList(groupCode, projectId,
                null, CollUtil.newHashSet(AdmObjectType.SPACE.getIndex()), null);
        if (CollectionUtil.isEmpty(classList)) {
        	return AdmResponse.success();
		}
        QueryCriteria queryCriteria = new QueryCriteria();
        ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);
        ObjectNode objectNode = objectMapper.createObjectNode();
        objectNode.put("graphCode", AdmRelationTypeEnum.SH2SP.getGraphCode());
        objectNode.put("relCode", AdmRelationTypeEnum.SH2SP.getRelCode());
        objectNode.put("objFrom", shaftId);
        objectNode.put("valid", Boolean.TRUE);
        queryCriteria.setCriteria(objectNode);
        List<ObjectRelation> objectRelations = DigitalRelationFacade.query(context.getGroupCode(),
                context.getProjectId(), context.getAppId(), context.getUserId(), queryCriteria);
        if (CollUtil.isEmpty(objectRelations)){
            return AdmResponse.success(new ArrayList<>());
        }
        Set<String> filterSpaceTypes = objectRelations.stream()
                .filter(objectRelation -> StrUtil.isNotBlank(objectRelation.getRelValue()))
                .map(ObjectRelation::getRelValue).collect(Collectors.toSet());
        if (CollUtil.isEmpty(filterSpaceTypes)){
            return AdmResponse.success(new ArrayList<>());
        }
        List<JSONObject> result = new ArrayList<>();
        for (ObjectTypeDefine objectTypeDefine : classList) {
            if (!filterSpaceTypes.contains(objectTypeDefine.getCode())){
                continue;
            }
        	JSONObject temp = new JSONObject();
            temp.put("objectType", objectTypeDefine.getCode());
            temp.put("objectTypeName", objectTypeDefine.getName());
            result.add(temp);
		}
        // 根据分区名称排序
        result = result.stream().sorted(CompareUtil.comparingPinyin(obj -> obj.getString("objectTypeName"))).collect(Collectors.toList());
        return AdmResponse.success(result);
    }
}
