package com.persagy.proxy.object.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.simple.client.DigitalObjectSimpleFacade;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.service.impl.AbstractAdmBaseServiceImpl;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.adm.utils.AdmEntityTransferUtil;
import com.persagy.proxy.adm.utils.AdmQueryCriteriaHelper;
import com.persagy.proxy.common.entity.DmpResult;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.dictionary.model.AdmDict;
import com.persagy.proxy.dictionary.model.AdmObjectType;
import com.persagy.proxy.dictionary.service.IAdmDictService;
import com.persagy.proxy.object.model.*;
import com.persagy.proxy.object.service.IAdmBuildingService;
import com.persagy.proxy.object.service.IAdmEquipmentService;
import com.persagy.proxy.object.service.IAdmFloorService;
import com.persagy.proxy.object.service.IAdmSystemService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * ADM 系统 实现类
 * @author lvxy
 * @date 2021/8/18
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AdmSystemServiceImpl extends AbstractAdmBaseServiceImpl<AdmSystem> implements IAdmSystemService {

    private final IAdmDictService dictService;
    private final IAdmEquipmentService equipmentService;
    private final IAdmBuildingService buildingService;
    private final IAdmFloorService floorService;
    /***
     * Description: 查询系统数据
     * @param request : 请求参数
     * @return : com.persagy.proxy.adm.request.AdmResponse
     * @author : lijie
     * @date :2021/11/2 14:04
     * Update By lijie 2021/11/2 14:04
     */
    @Override
    public AdmResponse query(AdmQueryCriteria request) {
        AdmResponse response = this.doQuery(AdmContextUtil.toDmpContext(), request, AdmSystem.class);
        // 系统需要补充分类名称属性
        ensureSpecialValues(AdmContextUtil.toDmpContext(), (List<AdmSystem>) response.getContent());
        return response;
    }

    @Override
    public void ensureSpecialValues(InstanceUrlParam context, List<AdmSystem> vos) {
        if(CollUtil.isEmpty(vos)) {
            return;
        }
        // 查询对象类型 - 只找到这个接口，应提供一个按编码查编码名称Map的接口
        AdmDict admDict = AdmDict.builder().type(AdmSystem.OBJ_TYPE).build();
        AdmResponse dicRs = dictService.queryCategory(context, admDict, AdmObjectType.class);
        List<AdmObjectType> dicList = (List<AdmObjectType>) dicRs.getContent();
        if(CollUtil.isEmpty(dicList)) {
            return;
        }
        // 转换为编码名称Map
        Map<String, String> codeNameMap = CollUtil.fieldValueAsMap(dicList, "code", "name");
        Map<String, AdmObjectType> codeNameMaps = CollUtil.fieldValueMap(dicList, "code");
        // 给系统赋值 - 同时收集设备对象，扩展设备对象赋值
        List<AdmEquipment> equipmentList = new ArrayList<>();
        for(AdmSystem vo:vos) {
            vo.setCategoryName(codeNameMap.get(vo.getClassCode()));
            if(codeNameMaps.get(vo.getClassCode()) != null){
                AdmSystemCategory admSystemCategory = new AdmSystemCategory();
                admSystemCategory.setCategoryName(codeNameMaps.get(vo.getClassCode()).getName());
                admSystemCategory.setCode(codeNameMaps.get(vo.getClassCode()).getCode());
                admSystemCategory.setProjectI(codeNameMaps.get(vo.getClassCode()).getProjectId());
                vo.setCategoryNames(admSystemCategory);
            }
            // 收集设备对象
            if(CollUtil.isEmpty(vo.getEquipmentList())) {
                continue;
            }
            equipmentList.addAll(vo.getEquipmentList());
        }
        // 对象扩展属性赋值
        equipmentService.ensureSpecialValues(context, equipmentList);
    }

    @Override
    public void processDmpCriteria(QueryCriteria dmpRequest) {
        /*ObjectNode criteria = dmpRequest.getCriteria();
        if (null==criteria){
            return;
        }
        if (criteria.has("floorId")){
            // 有楼层id过滤
            if(!criteria.get("floorId").toString().contains("$null")){
                ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
                ObjectNode relationFrom = objectMapper.createObjectNode();
                relationFrom.put("graphCode", GraphCodeEnum.MechInArch.name());
                relationFrom.put("relCode", RelCodeEnum.Sy2Fl.name());
                relationFrom.set("objTo",criteria.get("floorId"));
                criteria.set("relationFrom",relationFrom);
                criteria.remove("floorId");
                if (criteria.has("buildingId"))
                    criteria.remove("buildingId");
                return;
            }
        }
        if (criteria.has("buildingId")){
            // 有建筑id过滤
            ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
            ObjectNode relationFrom = objectMapper.createObjectNode();
            relationFrom.put("graphCode", GraphCodeEnum.MechInArch.name());
            relationFrom.put("relCode", RelCodeEnum.Sy2Bd.name());
            if(!criteria.get("buildingId").toString().contains("$null")) {
                relationFrom.set("objTo", criteria.get("buildingId"));
            }else{
                relationFrom.put("$bindFlag", false);
            }
            criteria.set("relationFrom",relationFrom);
            criteria.remove("buildingId");
        }*/
    }

    @Override
    public AdmResponse queryNewInternal(String buildingId, String floorId, AdmQueryCriteria request) {
        constructQueryNewParam(buildingId,floorId,request);
        QueryCriteria rwdQueryCriteria = AdmQueryCriteriaHelper.toDmpCriteria(request);
        if(JSONUtil.isNull(rwdQueryCriteria.getCriteria())){
            return AdmResponse.failure("请求参数错误");
        }
        if (StrUtil.isNotBlank(floorId) && "1".equals(floorId)){
            // 楼层id不为空且为1
            AdmResponse admResponse = queryNotSureObj(buildingId, rwdQueryCriteria);
            dealBdFlInfo(floorId,buildingId, (List<AdmSystem>) admResponse.getContent());
            return admResponse;
        }
        if(StrUtil.isEmpty(floorId) && StrUtil.isNotEmpty(buildingId) && "1".equals(buildingId)){
            // 楼层id为空且建筑id不为空且建筑id为1
            AdmResponse admResponse = queryNotSureObj(null, rwdQueryCriteria);
            dealBdFlInfo(floorId,buildingId, (List<AdmSystem>) admResponse.getContent());
            return admResponse;
        }
        return queryNewInternal(request);
    }

    /***
     * Description: 构建query-new接口的请求参数
     * @param buildingId : 建筑id
     * @param floorId : 楼层id
     * @param request : 请求参数
     * @return : void
     * @author : lijie
     * @date :2021/11/2 11:57
     * Update By lijie 2021/11/2 11:57
     */
    private void constructQueryNewParam(String buildingId, String floorId, AdmQueryCriteria request) {
        request.setName(AdmSystem.OBJ_TYPE);
        AdmQueryCriteria admQueryCriteriaFl = new AdmQueryCriteria();
        admQueryCriteriaFl.setName("floorList");
        List<AdmQueryCriteria> cascadeFlBd = new ArrayList<>(1);
        AdmQueryCriteria admQueryCriteriaBdFl = new AdmQueryCriteria();
        admQueryCriteriaBdFl.setName("building");
        cascadeFlBd.add(admQueryCriteriaBdFl);
        admQueryCriteriaFl.setCascade(cascadeFlBd);
        List<AdmQueryCriteria> cascade = new ArrayList<>(1);
        cascade.add(admQueryCriteriaFl);
        request.setCascade(cascade);
        // 楼层id不为空且楼层id不为1,加上关系筛选
        if (StrUtil.isNotEmpty(floorId) && !"1".equals(floorId)) {
            String filters = request.getFilters();
            if (StrUtil.isNotBlank(filters)){
                request.setFilters(filters+"; floorId='"+floorId+"'");
            }else {
                request.setFilters("floorId='"+floorId+"'");
            }
            return;
//
//            JSONObject relationFrom = new JSONObject();
//            relationFrom.put("relCode", "Sy2Fl");
//            relationFrom.put("graphCode", "MechInArch");
//            relationFrom.put("objTo", floorId);
//            criteria.putPOJO("relationFrom",relationFrom);
//            rwdQueryCriteria.setCriteria(criteria);
//            return rwdQueryCriteria;
        }
        // 楼层id为空且建筑id不为空且建筑id不为1,加上关系筛选
        if(StrUtil.isEmpty(floorId) && StrUtil.isNotEmpty(buildingId) && !"1".equals(buildingId)){
            String filters = request.getFilters();
            if (StrUtil.isNotBlank(filters)){
                request.setFilters(filters+";buildingId='"+buildingId+"'");
            }else {
                request.setFilters("buildingId='"+buildingId+"'");
            }
//            JSONObject relationFrom = new JSONObject();
//            relationFrom.put("relCode", "Sy2Bd");
//            relationFrom.put("graphCode", "MechInArch");
//            relationFrom.put("objTo", buildingId);
//            criteria.putPOJO("relationFrom",relationFrom);
//            rwdQueryCriteria.setCriteria(criteria);
//            return rwdQueryCriteria;
        }
    }

    /***
     * Description: 当楼层id和建筑id都为空时query-new接口的处理逻辑
     * @param rwdQueryCriteria : 请求参数
     * @return : com.persagy.proxy.adm.request.AdmResponse
     * @author : lijie
     * @date :2021/11/2 11:40
     * Update By lijie 2021/11/2 11:40
     */
    private AdmResponse queryNewInternal(AdmQueryCriteria rwdQueryCriteria) {
        AdmResponse syses = this.query(rwdQueryCriteria);
        if (CollUtil.isEmpty(syses.getContent())){
            syses.setContent(new ArrayList<>());
            return syses;
        }
        //处理数据 BuildingFloorInfo
        List<AdmSystem> admSystemList = (List<AdmSystem>) syses.getContent();
        admSystemList.forEach(admSystem -> {
            List<ObjectNode> buildingFloorInfoList = new ArrayList<>();
            List<AdmFloor> admFloorList = admSystem.getFloorList();
            if (CollUtil.isEmpty(admFloorList)){
                admSystem.setFloorList(null);
                admSystem.setBuildingFloorInfoList(buildingFloorInfoList);
                return;
            }
            admFloorList.forEach(admFloor -> {
                ObjectNode infobd = JsonNodeFactory.instance.objectNode();
                infobd.put("BuildID",admFloor.getBuilding()!=null?admFloor.getBuilding().getId() : "");
                infobd.put("BuildName",admFloor.getBuilding() != null ? admFloor.getBuilding().getLocalName() : "");
                if(!buildingFloorInfoList.contains(infobd)){
                    buildingFloorInfoList.add(infobd);
                }
                ObjectNode infobd1 = infobd.deepCopy();
                infobd1.put("FloorID",admFloor.getId());
                infobd1.put("FloorName",admFloor.getLocalName());
                buildingFloorInfoList.add(infobd1);
            });
            admSystem.setFloorList(null);
            admSystem.setBuildingFloorInfoList(buildingFloorInfoList);
        });
        syses.setContent(CollUtil.isEmpty(admSystemList) ? new ArrayList<>() : admSystemList);
        return syses;
    }

    /**
     * 查询不确定建筑/楼层的系统
     * @param buildingId
     * @param rwdQueryCriteria
     * @return
     */
    private AdmResponse queryNotSureObj(String buildingId, QueryCriteria rwdQueryCriteria){
        RequestData requestData = new RequestData();
        String classCode = rwdQueryCriteria.getCriteria().get("classCode").textValue();
        if(StrUtil.isNotEmpty(classCode)){
            requestData.setClassCode(classCode);
        }
        if(StrUtil.isNotEmpty(buildingId)){
            requestData.setBuildingId(buildingId);
        }
        requestData.setProjectId(AdmContextUtil.toDmpContext().getProjectId());
        requestData.setGraphCode(AdmContextUtil.toDmpContext().getGroupCode());
        requestData.setObjType(AdmSystem.OBJ_TYPE);
        requestData.setPage(rwdQueryCriteria.getPage());
        requestData.setSize(rwdQueryCriteria.getSize());
        Page<Map<String,Object>> result = DigitalObjectSimpleFacade.queryNotSureSystem(AdmContextUtil.toDmpContext().getGroupCode(), AdmContextUtil.toDmpContext().getProjectId(), AdmContextUtil.toDmpContext().getAppId(),null, requestData);
        if(CollUtil.isNotEmpty(result.getRecords())){
            AdmResponse response = new AdmResponse();
            response.setPageSize(Integer.parseInt(String.valueOf(result.getSize())));
            response.setPageNumber(Integer.parseInt(String.valueOf(result.getCurrent())));
            response.setResult(DmpResult.SUCCESS);
            response.setContent(AdmEntityTransferUtil.toAdmMultiEntity(result.getRecords(),null,AdmSystem.class));
            response.setTotal(result.getTotal());
            return response;
        }else{
            return AdmResponse.success();
        }
    }

    /**
     * 处理建筑楼层信息 建筑确定，楼层可为空
     * @param floorId
     * @param buildingId
     * @param admSystemList
     * @return
     */
    private void dealBdFlInfo(String floorId, String buildingId, List<AdmSystem> admSystemList){
        if(CollUtil.isEmpty(admSystemList)){
            return;
        }
        if(StrUtil.isEmpty(buildingId)){//处理成adm目标格式
            List<ObjectNode> nullList = new ArrayList<>(0);
            admSystemList.forEach(admSystem -> {
                admSystem.setBuildingFloorInfoList(nullList);
            });
            return;
        }
        AdmResponse buildings = null;
        if(StrUtil.isNotEmpty(buildingId)){
            AdmQueryCriteria admQueryCriteria = getAdmQueryCriteria(AdmBuilding.OBJ_TYPE, buildingId);
            buildings = buildingService.doQuery(AdmContextUtil.toDmpContext(), admQueryCriteria, AdmBuilding.class);
        }
        AdmResponse floors = null;
        if(StrUtil.isNotEmpty(floorId)){
            AdmQueryCriteria admQueryCriteria = getAdmQueryCriteria(AdmFloor.OBJ_TYPE, floorId);
            floors = floorService.query(admQueryCriteria);
        }

        ObjectNode buildingFloorInfo = JsonNodeFactory.instance.objectNode();
        if (CollUtil.isNotEmpty(buildings.getContent())) {
            AdmBuilding admBuilding = (AdmBuilding) buildings.getContent().get(0);
            buildingFloorInfo.put("BuildID",admBuilding.getId());
            buildingFloorInfo.put("BuildName",admBuilding.getLocalName());
        }
        if (null!=floors && CollUtil.isNotEmpty(floors.getContent())) {
            ObjectNode buildingFloorInfoFl = JsonNodeFactory.instance.objectNode();
            buildingFloorInfoFl = buildingFloorInfo.deepCopy();
            AdmFloor floor = (AdmFloor) floors.getContent().get(0);
            buildingFloorInfoFl.put("FloorID",floor.getId());
            buildingFloorInfoFl.put("FloorName",floor.getLocalName());
        }
        if(JSONUtil.isNull(buildingFloorInfo) || buildingFloorInfo.isNull() || !buildingFloorInfo.fieldNames().hasNext()){
            admSystemList.forEach(admSystem -> {
                admSystem.setBuildingFloorInfoList(new ArrayList<>(1));
            });
            return;
        }
        admSystemList.forEach(admSystem -> {
            admSystem.setBuildingFloorInfoList(Collections.singletonList(buildingFloorInfo));
        });
    }

    private AdmQueryCriteria getAdmQueryCriteria(String objType, String Id){
        AdmQueryCriteria admQueryCriteria = new AdmQueryCriteria();
        admQueryCriteria.setName(objType);
        admQueryCriteria.setFilters("id = " + Id);
        return  admQueryCriteria;
    }
}
