package com.persagy.proxy.report.controller;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.TextSimilarity;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
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.common.model.entity.BaseEntity;
import com.persagy.dmp.digital.entity.ObjectRelation;
import com.persagy.proxy.object.service.*;
import com.persagy.proxy.relation.model.ShaftSpaceVertical;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.service.*;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.object.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhangwencheng
 * 竖井相关接口
 */

@RestController
@RequestMapping("/shaft")
public class AdmEquipShaftController {

    @Autowired
    private IAdmSystemService systemService;
    @Autowired
    private IAdmEquipmentService equipmentService;
    @Autowired
    private IAdmShaftService shaftService;
    @Autowired
    private IAdmSpaceService spaceService;
    @Autowired
    private IAdmRelationService relationService;
    @Autowired
    private IAdmFloorService floorService;

    /**
     * 查询没有和当前竖井绑定的系统
     * @param shaftId
     * @param request
     */
    @PostMapping("/unshaft-in-sys")
    public AdmResponse unShaftSys(@RequestParam String shaftId, @RequestBody AdmQueryCriteria request) {
        request.setName(AdmSystem.OBJ_TYPE);
        // 设置关系条件
        request.resetRelationCond(true, "MechInArch", "Sy2Sh", shaftId, false);
        return systemService.query(request);
    }

    /**
     * 查询没有和当前竖井绑定的设备
     */
    @PostMapping(value = "/unshaft-in-eq")
    public AdmResponse unShaftEq(@RequestParam String shaftId, @RequestBody AdmQueryCriteria request) {
        request.setName(AdmEquipment.OBJ_TYPE);
        // 设置关系条件
        request.resetRelationCond(true, "MechInArch", "Eq2Sh", shaftId, false);
        return equipmentService.query(request);
    }

    /**
     * 查询没有和当前竖井贯通的其它竖井
     */
    @PostMapping(value = "/unshaft-through-shaft")
    public AdmResponse unShaftThroughShaft(@RequestParam String shaftId, @RequestBody AdmQueryCriteria request) {
        request.setName(AdmShaft.OBJ_TYPE);
        // 设置关系条件
        request.resetRelationCond(true, "ThroughRelationship", "Sh2Sh", shaftId, false);
        return shaftService.doQuery(AdmContextUtil.toDmpContext(), request, AdmShaft.class);
    }

    /**
     * 查询竖井关联的空间垂直交通关系
     * @param shaftSpaceVertical
     */
    @PostMapping("/shaft-vertical-space")
    public AdmResponse shaftSpaceVertical(@RequestBody ShaftSpaceVertical shaftSpaceVertical) {
        // 参数校验
        String buildingId = shaftSpaceVertical.getBuildingId();
        String shaftId = shaftSpaceVertical.getShaftId();
        String objectType = shaftSpaceVertical.getObjectType();
        Boolean aiSwitch = shaftSpaceVertical.getAiSwitch();
        if (StrUtil.isBlank(buildingId) || StrUtil.isBlank(objectType) || StrUtil.isBlank(shaftId)) {
            return AdmResponse.failure("必填项：buildingId（建筑id）、shaftId（竖井Id）、objectType(空间类型)");
        }
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        // 查询建筑下的楼层
        List<AdmFloor> floors = floorService.queryFloorInBuilding(context, buildingId);
        AdmResponse response = AdmResponse.success(floors);
        if(CollUtil.isEmpty(floors)) {
            return response;
        }
        // 查询竖井下的空间
        List<AdmSpace> spaces = spaceService.querySpaceInShaft(context, shaftId, objectType);
        if(CollUtil.isEmpty(spaces)) {
            return response;
        }
        // 查询楼层下的空间
        List<String> floorIds = CollUtil.getFieldValues(floors, BaseEntity.PROP_ID, String.class);
        Map<String, List<String>> floorMap = spaceService.querySpaceMapInFloors(context, floorIds, objectType);
        if(MapUtil.isEmpty(floorMap)) {
            return response;
        }
        // 计算并收集垂直交通关系
        groupSpaceToFloor(context, buildingId, floors, spaces, floorMap, objectType, aiSwitch);
        return response;
    }

    /**
     * 按楼层汇总空间信息
     * @param context
     * @param buildingId
     * @param floors
     * @param spaces
     * @param floorMap
     * @param objectType
     * @param aiSwitch
     */
    private void groupSpaceToFloor(InstanceUrlParam context, String buildingId, List<AdmFloor> floors, List<AdmSpace> spaces,
                                   Map<String, List<String>> floorMap, String objectType, Boolean aiSwitch) {
        Map<String, AdmSpace> spaceMap = spaces.stream().collect(Collectors.toMap(AdmSpace::getId, space -> space, (k1,k2)->k1));
        Set<String> spaceIds = spaceMap.keySet();
        // 如果需要AI：相似度匹配
        Map<String, List<AdmSpace>> aiSpaceMap = new HashMap<>();
        Set<String> allIds = CollUtil.newHashSet(spaceIds);
        if(BooleanUtil.isTrue(aiSwitch)) {
            // 匹配结果
            aiSpaceMap = matchingSpaces(context, buildingId, spaces, spaceIds, objectType);
            // 收集id
            for(String key:aiSpaceMap.keySet()) {
                List<AdmSpace> aiSpaces = aiSpaceMap.get(key);
                if(CollUtil.isEmpty(aiSpaces)) {
                    continue;
                }
                Set<String> aiSpaceIds = aiSpaces.stream().map(AdmSpace::getId).collect(Collectors.toSet());
                allIds.addAll(aiSpaceIds);
            }
        }
        // 查询有垂直交通关系的空间
        Map<String, Set<String>> trafficMap = spaceService.queryTrafficSpaceMap(context, allIds, objectType);
        // 组装到Floor中
        for(AdmFloor floor:floors) {
            // 获取楼层下的空间
            List<String> spInFls = floorMap.get(floor.getId());
            if(CollUtil.isEmpty(spInFls)) {
                continue;
            }
            Set<AdmSpace> spaceList = new HashSet<>();
            for(String spInFlId:spInFls) {
                // 取竖井中在本楼层的空间
                AdmSpace spInSh = spaceMap.get(spInFlId);
                if(spInSh == null || !floor.getId().equals(spInSh.getFloorId())) {
                    continue;
                }
                // 设置垂直交通关系
                spInSh.setSpaceIdList(trafficMap.getOrDefault(spInFlId,new HashSet<>()));
                spaceList.add(spInSh);
                // 获取此空间匹配的空间
                List<AdmSpace> matchSpaces = aiSpaceMap.get(spInFlId);
                if(CollUtil.isEmpty(matchSpaces)) {
                    continue;
                }
                for(AdmSpace matchSpace:matchSpaces) {
                    // 如果非本楼层的则跳过
                    if (!floor.getId().equals(matchSpace.getFloorId())){
                        continue;
                    }
                    if(spaceList.add(matchSpace)) {
                        // 设置垂直交通关系
                        matchSpace.setSpaceIdList(trafficMap.getOrDefault(matchSpace.getId(),new HashSet<>()));
                    }
                }
            }
            if(CollUtil.isEmpty(spaceList)) {
                floor.setSpaceList(new ArrayList<>());
                continue;
            }
            floor.setSpaceList(CollUtil.newArrayList(spaceList));
        }
        floors.sort((f1,f2)-> CompareUtil.compare(f2.getFloorSequenceID(),f1.getFloorSequenceID(),false));
    }

    /**
     * 根据相似度匹配空间
     * @param context
     * @param buildingId 匹配此建筑下的空间
     * @param spaces 按这些空间匹配
     * @param spaceIds
     * @param objectType
     * @return
     */
    private Map<String, List<AdmSpace>> matchingSpaces(InstanceUrlParam context, String buildingId, List<AdmSpace> spaces,
                                                       Set<String> spaceIds, String objectType) {
        final double matchingPercent = 0.9;
        Map<String, List<AdmSpace>> aiSpaceMap = new HashMap<>();
        // 查询建筑下的空间
        List<AdmSpace> spInBds = spaceService.querySpaceInBuilding(context, buildingId, objectType);
        // 按竖井下的空间，逐个计算每个空间匹配的空间
        for(AdmSpace space:spaces) {
            for(AdmSpace spInBd:spInBds) {
                // 已在竖井下的不用再匹配
                if (spaceIds.contains(spInBd)) {
                    continue;
                }
                // 字符串匹配度大于0.9的保留
                if ((StrUtil.isNotBlank(space.getLocalId())
                      && StrUtil.isNotBlank(spInBd.getLocalId())
                      && TextSimilarity.similar(space.getLocalId(), spInBd.getLocalId()) > matchingPercent)
                        || ( StrUtil.isNotBlank(space.getLocalName())
                          && StrUtil.isNotBlank(spInBd.getLocalName())
                          && TextSimilarity.similar(space.getLocalName(), spInBd.getLocalName()) > matchingPercent)) {
                    List<AdmSpace> ais = aiSpaceMap.get(space.getId());
                    if (CollUtil.isEmpty(ais)) {
                        ais = new ArrayList<>();
                        aiSpaceMap.put(space.getId(), ais);
                    }
                    spInBd.setIsAi(true);
                    ais.add(spInBd);
                }
            }
        }
        return aiSpaceMap;
    }

    /**
     * 计算 和当前竖井有关联的空间的垂直交通关系
     */
    @PostMapping("/vertical-space")
    public AdmResponse shaftVerticalSp(@RequestBody ShaftSpaceVertical shaftSpaceVertical) {
                String buildingId = shaftSpaceVertical.getBuildingId();
        String shaftId = shaftSpaceVertical.getShaftId();
        String objectType = shaftSpaceVertical.getObjectType();
        if (StrUtil.isBlank(buildingId) || StrUtil.isBlank(shaftId) || StrUtil.isBlank(objectType)) {
            return AdmResponse.failure("必填项：buildingId（建筑id）、shaftId（竖井Id），objectType(空间类型)");
        }
        // 查询竖井下的空间
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        QueryCriteria queryRequest = new QueryCriteria();
        ObjectNode criteriaRel = JsonNodeFactory.instance.objectNode();
        criteriaRel.put("graphCode", "ArchSubset");
        criteriaRel.put("relCode", "Sh2Sp");
        criteriaRel.put("relValue", objectType);
        criteriaRel.put("objFrom", shaftId);
        queryRequest.setCriteria(criteriaRel);
        List<ObjectRelation> relations = relationService.queryByCondition(context, queryRequest);
        if(CollUtil.isEmpty(relations)) {
            return AdmResponse.success();
        }
        // 收集空间ID
        List<String> spaceIds = relations.stream().map(ObjectRelation::getObjTo).collect(Collectors.toList());
        // TODO 异步调用垂直关系计算 public.is_vertically_overlap(#{projectId},#{buildingId},#{zoneType},ARRAY)

        return AdmResponse.success();
    }

}
