package com.persagy.proxy.object.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
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.model.QueryCriteria;
import com.persagy.dmp.basic.utils.JsonNodeUtils;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.digital.entity.ObjectDigital;
import com.persagy.proxy.adm.constant.AdmDictConstant;
import com.persagy.proxy.adm.request.*;
import com.persagy.proxy.adm.service.IAdmRelationService;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.adm.utils.ObjectNameUtil;
import com.persagy.proxy.common.entity.RelationDTO;
import com.persagy.proxy.object.model.AdmBuilding;
import com.persagy.proxy.object.model.AdmFloor;
import com.persagy.proxy.object.model.AdmSpace;
import com.persagy.proxy.object.service.IAdmBuildingService;
import com.persagy.proxy.object.service.IAdmFloorService;
import com.persagy.proxy.object.service.IAdmSpaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.ws.rs.QueryParam;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Adm 空间 API
 * @author lvxy
 * @date 2021/8/16
 */

@RestController
@RequestMapping("/object/zone")

public class AdmSpaceController {
    @Autowired
    private IAdmSpaceService service;
    @Autowired
    private IAdmBuildingService buildingService;
    @Autowired
    private IAdmRelationService relationService;
    @Autowired
    private IAdmFloorService floorService;



    /**
     * 统计
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/count")
    public AdmResponse count(@RequestBody AdmQueryCriteria request) throws Exception {
        request.setName(AdmSpace.OBJ_TYPE);
        request.setOnlyCount(true);
        //return service.doQuery( AdmContextUtil.toDmpContext(), request, AdmSpace.class);
        return service.query(request);
    }
    /**
     * 创建
     * @param createRequest
     * @return
     * @throws Exception
     */
    @PostMapping("/create")
    public AdmCreateResponse create(@RequestBody AdmCreateRequest<AdmSpace> createRequest) throws Exception {
        List<AdmSpace> vos = CollUtil.newArrayList(createRequest.getContent());
        String msg = null;
        for (AdmSpace admSpace : vos) {
            if(StrUtil.isEmpty(admSpace.getClassCode())){
                msg = "classCode不可以为空！";
                break;
            }
            if (StrUtil.isEmpty(admSpace.getName())) {
                admSpace.setName(ObjectNameUtil.objectName("空间-"));
            }
        }
        if(StrUtil.isEmpty(msg)){
            vos = service.doInsertExt(AdmContextUtil.toDmpContext(), AdmSpace.class, vos);
            return AdmCreateResponse.success(vos);
        }else{
            return AdmCreateResponse.failure(msg);
        }

    }

    /**
     * 根据ID删除
     * @param vos
     * @return
     * @throws Exception
     */
    @PostMapping("/delete")
    public AdmResponse delete( @RequestBody List<AdmSpace> vos) throws Exception {
        service.doDelete( AdmContextUtil.toDmpContext(), vos);
        QueryCriteria queryCriteria = new QueryCriteria();
        vos.forEach(vo -> {
            /** 清除空间和建筑楼层的的数据 */
            dealRelation(vo.getId(), queryCriteria,"Bd2Sp", false);
            dealRelation(vo.getId(), queryCriteria,"Fl2Sp", false);
            dealRelation(vo.getId(), queryCriteria,"Sp2Si", true);
        });
        return AdmResponse.success();
    }

    /**
     * 更新分区对象信息
     * @param createRequest
     * @return
     * @throws Exception
     */
    @PostMapping("/update")
    public AdmResponse update(@RequestBody AdmCreateRequest<AdmSpace> createRequest, @QueryParam("projectId") String projectId) throws Exception {
        List<AdmSpace> vos = CollUtil.newArrayList(createRequest.getContent());
        // 特殊处理一下AdmSpace的infos
        if (CollUtil.isEmpty(vos)){
            return AdmResponse.success(new ArrayList<>());
        }
        Map<String, Field> fieldMap = JsonNodeUtils.getFieldMap(AdmSpace.class);
        Map<String, Field> objFieldMap = JsonNodeUtils.getFieldMap(ObjectDigital.class);
        Set<String> fields = fieldMap.keySet();
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        for (AdmSpace space : vos) {
            Map<String, Object> infos = space.getInfos();
            if (MapUtil.isEmpty(infos)){
                continue;
            }
            Set<String> mapKeys = infos.keySet();
            for (String mapKey : mapKeys) {
                if ((AdmDictConstant.TABLE_INFOS.contains(mapKey)
                        && !AdmDictConstant.HEIGHT.equals(mapKey)
                        && (fieldMap.containsKey(mapKey)) || AdmDictConstant.SPECIAL_INFOS.contains(mapKey))
                        || AdmDictConstant.PIC.equals(mapKey)){
                    // 这些信息就算在infos也不更新,
                    // 和com.persagy.proxy.dictionary.service.impl.AbstractAdmDictBaseServiceImpl.handleObjectInfoPath
                    // 的判断逻辑保持一致
                    continue;
                }
                try{
                    if (fields.contains(mapKey) && infos.get(mapKey) instanceof ArrayList){
                        ReflectUtil.setFieldValue(space,fieldMap.get(mapKey),objectMapper.readValue(objectMapper.writeValueAsString(infos.get(mapKey)), ArrayNode.class));
                        continue;
                    }
                    if (fields.contains(mapKey)){
                        // 如果属性值存在
                        ReflectUtil.setFieldValue(space,fieldMap.get(mapKey),infos.get(mapKey));
                    }
                } catch (Exception e){
                    // 信息点传值有问题,直接移除
                    infos.remove(mapKey);
                }
            }
        }
        return service.doUpdate(vos);
    }

    /**
     * 查询
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/query")
    public ObjectNode query(@RequestBody AdmDCSQueryRequest request) throws Exception {
        AdmResponse response = service.doQuerySpaces(AdmContextUtil.toDmpContext(), request);
        ObjectNode objectNode = JsonNodeUtils.toObjectNode(response, null, null);
        if(StrUtil.isNotEmpty(request.getZoneType())){
            objectNode.put("zoneType", request.getZoneType());
        }
        return objectNode;
    	/*ObjectNode criteria = AdmQueryCriteriaHelper.toCriteria(null, request.getFilters());
    	List<OrderItem> orderItem = AdmQueryCriteriaHelper.toOrderItem(request.getOrders());
    	return this.spaceRelationInfoHandler.querySpaceInfo(request, criteria, orderItem);*/
    }

    /**
     * 查询业务空间的建筑楼层，包含受影响的空间数量
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/building-floor")
    public AdmResponse queryBuildingFloor(@RequestBody AdmQueryCriteria request) throws Exception {
        request.setName(AdmBuilding.OBJ_TYPE);
        //增加建筑默认排序
        request.setOrders("localName asc");
        AdmQueryCriteria criteriaFloor = new AdmQueryCriteria();
        criteriaFloor.setName(AdmFloor.OBJ_TYPE);

        AdmQueryCriteria criteriaSpace = new AdmQueryCriteria();
        criteriaSpace.setName("spaceList");
        criteriaSpace.setFilters("state = 1");

        criteriaFloor.setCascade(CollUtil.newArrayList(criteriaSpace));
        criteriaFloor.setOrders("floorSequenceID desc");
        request.setCascade(CollUtil.newArrayList(criteriaFloor));
        AdmResponse response = buildingService.doQueryBuildingFloor(AdmContextUtil.toDmpContext(), request);
        List<AdmBuilding> buildings = (List<AdmBuilding>) response.getContent();
        buildings.forEach(building -> {
            if(CollUtil.isNotEmpty(building.getFloor())){
                List<AdmFloor> floors = building.getFloor();
                floors.forEach(floor -> {
                    if(CollUtil.isNotEmpty(floor.getSpaceList())){
                        floor.setCount(floor.getSpaceList().size());
                        floor.setSpaceList(null);
                    }else{
                        floor.setCount(0);
                    }
                });
            }
        });

        return response;
    }

    /**
     * 修改业务空间对象和建筑楼层的关系
     * spaceId 业务空间id,id 楼层或建筑id,type 业务空间的类型
     * @param voList
     * @return
     * @throws Exception
     */
    @PostMapping("/update-fl-bd")
    public AdmResponse updateFlBd(@RequestBody List<AdmUpDataFloorAndBuildingRequests> voList, @QueryParam("projectId") String projectId) throws Exception {
        if(CollUtil.isEmpty(voList)){
            return AdmResponse.failure("不可以传入空数据");
        }
        //TODO 循环删除 需要改为 批量删除
        List<RelationDTO> RSpInBd_up = new ArrayList<>();
        List<RelationDTO> RSpInFl_up = new ArrayList<>();
        List<AdmSpace> space_up = new ArrayList<>();
        QueryCriteria queryCriteria = new QueryCriteria();
        voList.stream().forEach(requestData -> {
            String spaceId = requestData.getSpaceId();
            String id = requestData.getId();
            String type = requestData.getType();//classCode

            //更新实体
            AdmSpace space = new AdmSpace();
            space.setId(spaceId);
            space.setObjectType(AdmSpace.OBJ_TYPE);
            space.setClassCode(type);

            /** 清除空间和建筑楼层的的数据 */
            dealRelation(spaceId, queryCriteria,"Bd2Sp", false);
            dealRelation(spaceId, queryCriteria,"Fl2Sp", false);

            if(StrUtil.isNotEmpty(id)){
                if(id.startsWith("Fl") && StrUtil.isNotEmpty(spaceId)){
                    AdmQueryCriteria admQueryCriteria = new AdmQueryCriteria();
                    admQueryCriteria.setName(AdmFloor.OBJ_TYPE);
                    admQueryCriteria.setFilters("id = '"+id+"'");
                    AdmResponse admResponseFl = floorService.query(admQueryCriteria);

                    if(CollUtil.isNotEmpty(admResponseFl.getContent())){
                        AdmFloor floor = (AdmFloor) admResponseFl.getContent().get(0);
                        if (floor!=null){
                            //更新关系
                            RelationDTO rBd_up = new RelationDTO();
                            rBd_up.setObjTo(spaceId);
                            rBd_up.setRelCode("Bd2Sp");
                            rBd_up.setGraphCode("ArchSubset");
                            rBd_up.setObjFrom(floor.getBuildingId());
                            RSpInBd_up.add(rBd_up);

                            RelationDTO rFl_up = new RelationDTO();
                            rFl_up.setObjTo(spaceId);
                            rFl_up.setRelCode("Fl2Sp");
                            rFl_up.setGraphCode("ArchSubset");
                            rFl_up.setObjFrom(floor.getId());
                            RSpInFl_up.add(rFl_up);

                            //楼层 建筑信息点维护
                            space.setBuildingId(floor.getBuildingId());
                            space.setFloorId(floor.getId());
                            space_up.add(space);
                        }
                    }
                }else if(id.startsWith("Bd")){
                    //更新关系
                    QueryCriteria criteria = new QueryCriteria();
                    ObjectNode node = JsonNodeFactory.instance.objectNode();
                    //删除关系 然后重建
                    node.put("relCode", "Bd2Sp");
                    node.put("objTo", "spaceId");
                    node.put("graphCode", "ArchSubset");
                    criteria.setCriteria(node);
                    relationService.doDelete(AdmContextUtil.toDmpContext(), criteria);

                    RelationDTO rBd_up = new RelationDTO();
                    rBd_up.setObjTo(spaceId);
                    rBd_up.setRelCode("Bd2Sp");
                    rBd_up.setGraphCode("ArchSubset");
                    rBd_up.setObjFrom(id);
                    RSpInBd_up.add(rBd_up);

                    //楼层 建筑信息点维护
                    space.setBuildingId(id);
                    Map<String, Object> info = new HashMap<>(1);
                    info.put("$remove",Arrays.asList("floorId"));
                    space.setInfos(info);
                    space_up.add(space);
                }
            }else{
                //楼层 建筑信息点维护 清除
                Map<String, Object> info = new HashMap<>(1);
                info.put("$remove",Arrays.asList("floorId","buildingId"));
                space.setInfos(info);
                space_up.add(space);
            }
        });
        service.doUpdate( AdmContextUtil.toDmpContext(), AdmSpace.class, space_up);
        relationService.doSave( AdmContextUtil.toDmpContext(), RSpInBd_up);
        relationService.doSave( AdmContextUtil.toDmpContext(), RSpInFl_up);
        return AdmResponse.success(space_up);
    }

    /**
     * 更新分区对象信息-Outline
     * @param createRequest
     * @return
     * @throws Exception
     */
    @PostMapping("/update-outline")
    public AdmResponse updateOutLine(@RequestBody AdmCreateRequest<AdmSpace> createRequest) throws Exception {
        List<AdmSpace> vos = CollUtil.newArrayList(createRequest.getContent());
        /*vos = service.doUpdate( AdmContextUtil.toDmpContext(), AdmSpace.class, vos);
        //更新计算关系ZoneSpaceBaseService.upDateOutline
        service.processRelationType(vos);
        return AdmResponse.success(vos);*/
        return service.updateOutLine(vos);
    }

    /**
     * 查询空间信息-outline 级联查询：建筑（building），楼层（floor），空间类型（objectType）
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/query-outline")
    public ObjectNode queryOutline(@RequestBody AdmDCSQueryRequest request) throws Exception {
        request.setName(AdmSpace.OBJ_TYPE);
        request.setProjection(null);
        List<String> list = new ArrayList<>();
        list.add("id");
        list.add("name");
        list.add("localId");
        list.add("localName");
        list.add("outline");
        list.add("classCode");
        list.add("buildingId");
        list.add("floorId");
        list.add("state");
        list.add("floorSequenceId");
        list.add("modelId");
        list.add("infos");
        list.add("properties");
        request.setProjection(list);
        AdmResponse response = service.doQuerySpaces(AdmContextUtil.toDmpContext(), request);
        ObjectNode objectNode = JsonNodeUtils.toObjectNode(response, null, null);
        if(StrUtil.isNotEmpty(request.getZoneType())){
            objectNode.put("zoneType", request.getZoneType());
        }
        if(StrUtil.isNotEmpty(request.getFloorId())){
            objectNode.put("floorId", request.getFloorId());
        }
        if(StrUtil.isNotEmpty(request.getBuildingId())){
            objectNode.put("buildingId", request.getBuildingId());
        }
        return objectNode;
    }


    /**
     * 获取项目下已有的空间类型
     *
     * @return
     * @throws Exception
     */
    @PostMapping("/space-type")
    public List<JSONObject> querySpaceType() throws Exception {
        return service.doQuerySpaceTypes( AdmContextUtil.toDmpContext());
    }

    /**
     * 查询业务空间所有类型
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/type")
    public ObjectNode queryType(@RequestBody AdmDCSQueryRequest request) throws Exception {
        AdmResponse response = service.doQueryType( AdmContextUtil.toDmpContext(), request);
        ObjectNode objectNode = JsonNodeUtils.toObjectNode(response, null, null);
        if(StrUtil.isNotEmpty(request.getZoneType())){
            objectNode.put("zoneType", request.getZoneType());
        }
        return objectNode;
    }


    /**
     * 上传EXCEL 识别镜头信息点
     *
     * @param
     * @return
     * @throws Exception
     */
    @PostMapping("/import")
    public AdmResponse importExcel() throws Exception {
        return null;
    }


    private void dealRelation(String spaceId, QueryCriteria queryCriteria, String relCode, Boolean isObjFrom){
        ObjectNode rBd = JsonNodeFactory.instance.objectNode();
        if(isObjFrom){
            rBd.put("objFrom",spaceId);
        }else{
            rBd.put("objTo",spaceId);
        }

        rBd.put("relCode",relCode);
        queryCriteria.setCriteria(rBd);
        relationService.doDelete( AdmContextUtil.toDmpContext(), queryCriteria);
    }
}
