package com.persagy.proxy.adm.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.helper.SpringHelper;
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.AdmObjectType;
import com.persagy.proxy.adm.constant.GraphCodeEnum;
import com.persagy.proxy.adm.constant.RelCodeEnum;
import com.persagy.proxy.adm.request.AdmDCSQueryRequest;
import com.persagy.proxy.adm.strategy.RelationObjectContext;
import com.persagy.proxy.report.service.IRelationReportService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 
 * @version 1.0.0
 * @company persagy 
 * @author zhangqiankun
 * @date 2021年10月18日 下午6:04:24
 */
@Component
@RequiredArgsConstructor
public class SpaceRelationInfoHandler {

	private final RelationObjectContext relationObjectContext;
	
	private final IRelationReportService relationReportService;

	/**
	 * 查询
	 *
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public JSONObject querySpaceInfo(AdmDCSQueryRequest request, ObjectNode criteria, List<OrderItem> orderItem) throws Exception {
		List<ObjectNode> resultList = null;
		String groupCode = AppContext.getContext().getGroupCode();
		String projectId = AppContext.getContext().getProjectId();
		
		JSONObject result = new JSONObject();
		result.put("result", "success");
		
		String floorId = request.getFloorId();
		String buildingId = request.getBuildingId();
		Set<String> zoneTypeList = StrUtil.isNotEmpty(request.getZoneType()) ? Sets.newHashSet(request.getZoneType()) 
				: (request.getZoneTypeList() == null ? Sets.newHashSet() : request.getZoneTypeList());
		
		if (StrUtil.isNotBlank(buildingId) && StrUtil.isNotBlank(floorId) && !"isnull".equals(floorId)) {
			// 当建筑ID不为空、楼层ID不为空时
			String graphAndRelKey = GraphCodeEnum.ArchForArch.name() + AdmCommonConstant.UNDERLINE + RelCodeEnum.Sp2Fl.name();
			List<ObjectDigital> allRelations = this.relationObjectContext.queryAllRelations(groupCode, projectId, graphAndRelKey, null, Sets.newHashSet(buildingId), null);
			if (CollectionUtil.isNotEmpty(allRelations)) {
				resultList = this.transferSpaceInfo(allRelations, buildingId, floorId);
			}
			
		} else if (StrUtil.isNotBlank(buildingId) && StrUtil.isNotBlank(floorId) && "isnull".equals(floorId)) {
			// 当建筑ID不为空、楼层ID为空时
			this.querySpaceInfo(request, groupCode, projectId, buildingId, zoneTypeList, orderItem);
			
		} else if (StrUtil.isNotBlank(buildingId) && StrUtil.isBlank(floorId) && !"isnull".equals(buildingId)) {
			// 当建筑ID不为空、楼层ID为空时
			String graphAndRelKey = GraphCodeEnum.ArchForArch.name() + AdmCommonConstant.UNDERLINE + RelCodeEnum.Sp2Bd.name();
			List<ObjectDigital> allRelations = this.relationObjectContext.queryAllRelations(groupCode, projectId, graphAndRelKey, null, Sets.newHashSet(buildingId), null);
			if (CollectionUtil.isNotEmpty(allRelations)) {
				resultList = this.transferSpaceInfo(allRelations, buildingId, null);
			}
			
		} else if (StrUtil.isNotBlank(buildingId) && StrUtil.isBlank(floorId) && "isnull".equals(buildingId)) {
			// 当建筑ID为空、楼层ID为空时
			resultList = this.querySpaceInfo(request, criteria, groupCode, projectId, zoneTypeList, orderItem);
			
		} else if (StrUtil.isBlank(buildingId) && StrUtil.isBlank(floorId)) {
			// 直接获取所有的空间数据
			List<ObjectNode> spacelist = this.relationReportService.queryObjects(criteria, groupCode, projectId, null, zoneTypeList, 
					Sets.newHashSet(AdmObjectType.SPACE.getIndex()), orderItem);
			resultList = this.fillSpaceInfo(spacelist, null, null);
		}
		
		result.put("zoneType", request.getZoneType());
		result.put("floorId", request.getFloorId());
		result.put("total", CollectionUtil.isEmpty(resultList) ? 0 : resultList.size());
		result.put("content", CollectionUtil.isEmpty(resultList) ? Lists.newArrayList() : resultList);
		return result;
	}
	
	/**
	 * 获取空间信息，当楼层ID为空，建筑ID不为空时
	 * @param request
	 * @param groupCode
	 * @param projectId
	 * @param buildingId
	 * @param zoneTypeList
	 * @param orderItem
	 * @return
	 */
	private List<ObjectNode> querySpaceInfo(AdmDCSQueryRequest request, String groupCode, String projectId, String buildingId, 
			Set<String> zoneTypeList, List<OrderItem> orderItem) {
		List<ObjectNode> resultList = null;
		Set<String> spaceIds = new HashSet<String>();
		Set<String> floorIds = new HashSet<String>();
		Set<String> notBuildSpace = new HashSet<String>();
		// 获取所有的楼层ID集合
		List<ObjectRelation> relationObjects = this.queryObjectRelation(groupCode, projectId, GraphCodeEnum.ArchForArch.name(), RelCodeEnum.Fl2Bd.name(), null, Sets.newHashSet(buildingId));
		
		// 获取所有楼层下的空间数据
		if (CollectionUtil.isNotEmpty(relationObjects)) {
			for (ObjectRelation objectRelation : relationObjects) {
				floorIds.add(objectRelation.getObjFrom());
			}
			
			// 根据楼层ID，获取所有的空间ID
			relationObjects = this.queryObjectRelation(groupCode, projectId, GraphCodeEnum.ArchForArch.name(), RelCodeEnum.Sp2Fl.name(), null, floorIds);
			for (ObjectRelation objectRelation : relationObjects) {
				spaceIds.add(objectRelation.getObjFrom());
			}
			// 再获取此建筑下，不是这些空间的空间
			relationObjects = this.queryObjectRelation(groupCode, projectId, GraphCodeEnum.ArchForArch.name(), RelCodeEnum.Sp2Bd.name(), null, Sets.newHashSet(buildingId));
			for (ObjectRelation objectRelation : relationObjects) {
				if (!spaceIds.contains(objectRelation.getObjFrom())) {
					notBuildSpace.add(objectRelation.getObjFrom());
				}
			}
			
			if (CollectionUtil.isNotEmpty(notBuildSpace)){
				// 获取所有的对象数据
				resultList = this.relationReportService.queryObjects(null, groupCode, projectId, notBuildSpace, zoneTypeList, 
    					Sets.newHashSet(AdmObjectType.SPACE.getIndex()), orderItem);
    			this.fillSpaceInfo(resultList, buildingId, null);
            }
		} else {
			// 获取所有的空间数据
			String graphAndRelKey = GraphCodeEnum.MechInArch.name() + AdmCommonConstant.UNDERLINE + RelCodeEnum.Eq2Fl.name();
			List<ObjectDigital> allRelations = this.relationObjectContext.queryAllRelations(groupCode, projectId, graphAndRelKey, null, Sets.newHashSet(buildingId), null);
			if (CollectionUtil.isNotEmpty(allRelations)) {
				resultList = this.transferSpaceInfo(allRelations, buildingId, null);
			}
		}
		
		spaceIds.clear();
		notBuildSpace.clear();
		return resultList;
	}
	

	/**
	 * 获取空间信息，当楼层ID为空，建筑ID为空时
	 * 
	 * @param request
	 * @param groupCode
	 * @param projectId
	 * @return
	 */
	private List<ObjectNode> querySpaceInfo(AdmDCSQueryRequest request, ObjectNode criteria, String groupCode, String projectId, 
			Set<String> zoneTypeList, List<OrderItem> orderItem) {
		List<ObjectNode> resultList = null;
		// 获取所有的建筑ID集合
		List<ObjectNode> buildList = this.relationReportService.queryObjects(null, groupCode, projectId, null, null, 
				Sets.newHashSet(AdmObjectType.BUILDING.getIndex()), orderItem);
		if (CollectionUtil.isNotEmpty(buildList)) {
			for (ObjectNode objectNode : buildList) {
				String buildingId = objectNode.get("id").asText();
				// 获取所有的空间数据
				String graphAndRelKey = GraphCodeEnum.MechInArch.name() + AdmCommonConstant.UNDERLINE + RelCodeEnum.Eq2Fl.name();
				List<ObjectDigital> allRelations = this.relationObjectContext.queryAllRelations(groupCode, projectId, graphAndRelKey, null, Sets.newHashSet(buildingId), null);
				if (CollectionUtil.isNotEmpty(allRelations)) {
					// 获取所有的对象数据
					resultList = this.transferSpaceInfo(allRelations, buildingId, null);
				}
			}
		} else {
			// 获取所有的空间数据
			List<ObjectNode> spacelist = this.relationReportService.queryObjects(criteria, groupCode, projectId, null, zoneTypeList, 
					Sets.newHashSet(AdmObjectType.SPACE.getIndex()), orderItem);
			resultList = this.fillSpaceInfo(spacelist, null, null);
		}
		
		return resultList;
	}
	
	/**
	 * 转换数据
	 * 
	 * @param allRelations
	 * @param buildingId
	 * @param floorId
	 * @return
	 */
	private List<ObjectNode> transferSpaceInfo(List<ObjectDigital> allRelations, String buildingId, String floorId) {
		if (CollectionUtil.isEmpty(allRelations)) {
			return null;
		}
		
		List<ObjectNode> resultList = new ArrayList<ObjectNode>();
		ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
		for (ObjectDigital objectDigital : allRelations) {
			ObjectNode result = objectMapper.createObjectNode();
			
			ObjectNode infos = objectDigital.getInfos();
			result.put("bimLocation", infos.has("bimLocation") ? infos.get("bimLocation").asText() : null);
			result.put("height", infos.has("height") ? infos.get("height").asText() : null);
			result.put("outline", infos.has("outline") ? infos.get("outline").asText() : null);
			result.put("floorId", "");
			result.put("buildingId", buildingId);
			result.put("classCode", objectDigital.getClassCode());
			result.put("id", objectDigital.getId());
			result.put("projectId", objectDigital.getProjectId());
			result.put("localName", objectDigital.getLocalName());
			result.put("name", objectDigital.getName());
			result.putPOJO("infos", new JSONObject());
			result.putPOJO("statistics", new JSONObject());
			result.put("state", (objectDigital.getValid() == null || objectDigital.getValid() == 1) ? 0 : 1);
			result.put("createTime", objectDigital.getCreationTime().toString("yyyy-MM-dd HH:mm:ss"));
			
			resultList.add(result);
		}
		
		resultList.sort((r1, r2) -> {
			return r2.get("createTime").asText().compareTo(r1.get("").asText());
		});
		
		return resultList;
	}

	/**
	 * 数据填充
	 * 
	 * @param queryObjects
	 * @param buildingId
	 * @param floorId
	 * @return
	 */
	private List<ObjectNode> fillSpaceInfo(List<ObjectNode> queryObjects, String buildingId, String floorId) {
		if (CollectionUtil.isEmpty(queryObjects)) {
			return null;
		}
		
		List<ObjectNode> resultList = new ArrayList<ObjectNode>();
		ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
		
		for (ObjectNode objectNode : queryObjects) {
			ObjectNode result = objectMapper.createObjectNode();
			String infos = objectNode.has("infos") ? objectNode.get("infos").asText() : null;
			if (StrUtil.isNotBlank(infos)) {
				JSONObject infoObject = JSONObject.parseObject(infos);
				
				result.put("bimLocation", infoObject.getString("bimLocation"));
				result.put("height", infoObject.getDouble("height"));
				result.put("outline", infoObject.getString("outline"));
				result.put("floorId", floorId);
				result.put("buildingId", buildingId);
			}
			
			result.put("classCode", objectNode.has("classCode") ? objectNode.get("classCode").asText() : null);
			result.put("id", objectNode.has("id") ? objectNode.get("id").asText() : null);
			result.put("projectId", objectNode.has("projectId") ? objectNode.get("projectId").asText() : null);
			result.put("localName", objectNode.has("localName") ? objectNode.get("localName").asText() : null);
			result.put("name", objectNode.has("name") ? objectNode.get("name").asText() : null);
			
			Long creationTime = objectNode.has("creationTime") ? objectNode.get("creationTime").asLong() : null;
			result.put("createTime", creationTime == null ? null : new DateTime(creationTime).toString());
			result.putPOJO("infos", new JSONObject());
			result.putPOJO("statistics", new JSONObject());
			result.put("state", objectNode.has("valid") ? (objectNode.get("valid").asInt(0) == 1 ? 0 : 1) : 0);
			
			resultList.add(result);
		}
		
		return queryObjects;
	}
	
	/**
	 * 获取关系数据
	 * 
	 * @param groupCode
	 * @param projectId
	 * @param graphCode
	 * @param relCode
	 * @param objFroms
	 * @param objTos
	 * @return
	 */
	private List<ObjectRelation> queryObjectRelation(String groupCode, String projectId, String graphCode, String relCode, Set<String> objFroms, Set<String> objTos) {
		List<ObjectRelation> relationObjects = this.relationReportService.findRelationObjects(groupCode, projectId, graphCode, relCode, objFroms, objTos);
		return CollectionUtil.isEmpty(relationObjects) ? Lists.newArrayList() : relationObjects;
	}

}
