package com.persagy.proxy.dictionary.controller;

import cn.hutool.core.collection.CollUtil;
import com.persagy.dmp.define.entity.ObjectInfoCollect;
import com.persagy.proxy.adm.constant.AdmDictCategoryEnum;
import com.persagy.proxy.adm.constant.AdmDictConstant;
import com.persagy.proxy.adm.request.AdmCreateRequest;
import com.persagy.proxy.adm.request.AdmDictQueryCriteria;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.dictionary.model.*;
import com.persagy.proxy.dictionary.service.IAdmDictService;
import com.persagy.proxy.object.model.*;
import com.persagy.proxy.object.service.IAdmEquipmentService;
import com.persagy.proxy.object.service.IAdmShaftService;
import com.persagy.proxy.object.service.IAdmSpaceService;
import com.persagy.proxy.object.service.IAdmSystemService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

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

/**
 * @ClassName AdmDictController
 * @Description: 字典查询
 * @Author linhuili
 * @Date 2021/8/31 18:21
 * @Version V1.0
 **/
@RestController
@RequestMapping("/dict")
@Slf4j
public class AdmDictController {

    @Autowired
    private IAdmDictService service;
    @Autowired
    private IAdmEquipmentService equipmentService;
    @Autowired
    private IAdmSpaceService spaceService;
    @Autowired
    private IAdmShaftService shaftService;
    @Autowired
    private IAdmSystemService systemService;

    /**
     * 字典类型查询:所有设备类型、部件类型、系统类型、专业类型
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/category")
    public AdmResponse queryCategory(@RequestBody AdmDict request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        if(StringUtils.isEmpty(request.getType())){
            throw new Exception("type不能为空");
        }
        return service.queryCategory(context,request, AdmObjectType.class);
    }


    /**
     * 批量处理字典信息操作：方案设定（BDTP暂不支持）
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/dict-batch")
    public AdmResponse dictBatch( @RequestBody AdmCreateRequest<AdmDictBatch> request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        //方案设定：方案id ：全新设定（schemeZero）、方案1（schemeOne）、方案2（schemeTwo），
        //"注意SchemeId为必填字段 ，优先级在列表中[R,S,M] ,一级标签[技术参数，基本参数] 列表为String类型
        return AdmResponse.success(new ArrayList<>());
    }

    /**
     * 查询项目下类型的信息点
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/query")
    public AdmResponse query(@RequestBody AdmDictQueryCriteria request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        if(StringUtils.isNotEmpty(request.getLabslType())){
            request.setName(request.getLabslType());
        }
        if(StringUtils.isNotEmpty(request.getType())){
            request.setName(request.getType());
        }
        return service.query(context, request, AdmDictConstant.CLASS_CODE, AdmObjectInfo.class);
    }


    /**
     * 查询设备对应的设备族（废弃）
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/family/query")
    @Deprecated
    public AdmResponse familyQuery(@RequestBody AdmQueryCriteria request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        return AdmResponse.success(new ArrayList<>());
    }

    /**
     * 重置项目下所有得定制信息点
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/reset-dic")
    public AdmResponse resetDic(@RequestBody AdmDictQueryCriteria request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        return service.resetDic(context,request,null,AdmObjectInfo.class);
    }


    /**
     * 根据类型，项目id重置信息点
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/reset-type")
    public AdmResponse resetType(@RequestBody AdmDictQueryCriteria request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        if(StringUtils.isEmpty(request.getType())){
            throw new Exception("type不能为空");
        }
        request.setName(request.getType());
        return service.resetDic(context,request,AdmDictConstant.CLASS_CODE,AdmObjectInfo.class);
    }

    /**
     * 设置-项目定制化字典
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/setting-dic-project")
    public AdmResponse settingDicProject(@RequestBody AdmCreateRequest<AdmDefFuncIdGather> request) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        return service.settingDicProject(context,request, ObjectInfoCollect.class);
    }

    /**
     * 查询项目下已有的设备类型带系统
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/system/equip/category")
    @Deprecated
    public AdmResponse querySystemEquipTree(@RequestBody AdmDictQueryCriteria request) throws Exception {
        return querySystemEquipTree(AdmContextUtil.toDmpContext(),request,AdmObjectType.class);
    }

    /**
     * 查询类型下所有字典信息 M 和 L 类型,包括自定义信息点
     * @param dictTypeList
     * @return
     * @throws Exception
     */
    @PostMapping("/morl/query")
    @Deprecated
    public AdmResponse queryMorlDict(@RequestBody List<String> dictTypeList) throws Exception {
        // 组装上下文条件
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        if(CollUtil.isEmpty(dictTypeList)){
            return AdmResponse.success(new ArrayList<>());
        }
        //查询指定类型下的信息点
        return service.queryMorlDict(context,dictTypeList);
    }

    /**
     * 获取不能同步到物理世界对象的数量
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/data-count")
    @Deprecated
    public AdmResponse queryNotSyncDmpObjects(@RequestBody AdmDictQueryCriteria request) throws Exception {
        return AdmResponse.success(new ArrayList<>());
    }

    /**
     * 需采集信息同步到所有项目
     * @return
     * @throws Exception
     */
    @GetMapping("/syn-dic-project")
    @Deprecated
    public AdmResponse syncProjectObjectInfo() throws Exception {
        return AdmResponse.success(new ArrayList<>());
    }

    /**
     * 需采集信息同步到所有项目
     * @return
     * @throws Exception
     */
    @PostMapping("/delivered/infos")
    @Deprecated
    public AdmResponse queryDictDeliveredInfos(@RequestBody AdmDictDeliverieInfosRequest request) throws Exception {
        if(StringUtils.isEmpty(request.getObjType())){
            return AdmResponse.success("对象类型不可以为空");
        }
        if(StringUtils.isEmpty(request.getClassCode())){
            return AdmResponse.success("类型不可以为空");
        }
        Map<String, AdmObjectInfo> admObjectInfoMap = service.queryDictDeliveredInfos(AdmContextUtil.toDmpContext(), request, AdmObjectInfo.class);

        //初始化待交付的信息点,id,name,localId,localName 无论是否有值默认展示，兼容历史逻辑
        List<AdmObjectInfo> deliveredInfos = new ArrayList<>();
        List<String> deliveredCodes = new ArrayList<>();
        service.initDeliveredInfos(admObjectInfoMap, deliveredInfos, deliveredCodes);
        String objType = request.getObjType();
        if("equipment".equals(objType)){
            //查询已交付的设备信息点
            return getAdmEquipDeliveredInfo(AdmContextUtil.toDmpContext(),request, admObjectInfoMap,deliveredInfos,deliveredCodes);
        }
        if("space".equals(objType)){
            //查询已交付的空间信息点
            return getAdmSpaceDeliveredInfo(AdmContextUtil.toDmpContext(),request, admObjectInfoMap,deliveredInfos,deliveredCodes);
        }
        if("system".equals(objType)){
            //查询已交付的系统信息点
            return getAdmSystemDeliveredInfo(AdmContextUtil.toDmpContext(),request, admObjectInfoMap,deliveredInfos,deliveredCodes);
        }
        if("shaft".equals(objType)){
            //查询已交付的竖井信息点
            return getAdmShaftDeliveredInfo(AdmContextUtil.toDmpContext(),request, admObjectInfoMap,deliveredInfos,deliveredCodes);
        }
        return AdmResponse.success(new ArrayList<>());
    }

    /**
     * 查询项目下已有的系统设备类型树
     * @param context
     * @param request
     * @param clazz
     * @return
     * @throws Exception
     */
    private <T> AdmResponse querySystemEquipTree(InstanceUrlParam context, AdmDictQueryCriteria request, Class<T> clazz) throws Exception {
        //查询项目下已有的设备类型
        request.setName(AdmEquipment.OBJ_TYPE);
        AdmResponse dictResponse = equipmentService.queryEquipClassCode(context, request, AdmEquipment.class);
        List<String> classCodes = (List<String>)dictResponse.getContent();
        if(CollUtil.isEmpty(classCodes)){
            return AdmResponse.success(new ArrayList<>());
        }
        Map<String, Set<String>> classCodeMap = classCodes.stream().collect(Collectors.groupingBy(item->item.substring(0,4),Collectors.toSet()));
        //查询系统设备类树
        AdmDict admDict = new AdmDict(AdmDictCategoryEnum.SYSTEM_EQUIP.getValue());
        AdmResponse categoryResponse = service.queryCategory(context, admDict, clazz);
        List<AdmObjectType> objectTypes = (List<AdmObjectType>) categoryResponse.getContent();
        if(CollUtil.isEmpty(objectTypes)){
            return AdmResponse.success(new ArrayList<>());
        }
        //过滤设备实体中不存在的类型
        Iterator<AdmObjectType> it = objectTypes.iterator();
        while(it.hasNext()){
            // 系统
            AdmObjectType systemType = it.next();
            // 设备类型
            List<AdmObjectType> equipmentTypes = systemType.getChildren();
            // 当前有的设备类型
            Set<String> classes = classCodeMap.get(systemType.getCode());
            if(CollUtil.isEmpty(equipmentTypes) || CollUtil.isEmpty(classes)){
                it.remove();
                continue;
            }
            Iterator<AdmObjectType> equipmentTypeIterator = equipmentTypes.iterator();
            while (equipmentTypeIterator.hasNext()){
                AdmObjectType equipmentType = equipmentTypeIterator.next();
                // 不包含的移除掉
                if(!CollUtil.contains(classes, equipmentType.getCode())){
                    equipmentTypeIterator.remove();
                }
            }
            // 如果所有的都没了，也去掉系统
            if(CollUtil.isEmpty(equipmentTypes)) {
                it.remove();
                continue;
            }
        }
        return AdmResponse.success(objectTypes);
    }

    /**
     * 查询已交付的设备信息点
     * @param context
     * @param request
     */
    private AdmResponse getAdmEquipDeliveredInfo(InstanceUrlParam context,AdmDictDeliverieInfosRequest request, Map<String, AdmObjectInfo> admObjectInfoMap,List<AdmObjectInfo> deliveredInfos,List<String> deliveredCodes){
        AdmQueryCriteria admQueryCriteria = service.commbineObjectQueryCriteria(request);
        AdmResponse response = equipmentService.query(admQueryCriteria);
        List<AdmEquipment> content = (List<AdmEquipment>)response.getContent();
        if(CollUtil.isEmpty(content)){
            return AdmResponse.success(new ArrayList<>());
        }
        //统计有值的信息点
        for (AdmEquipment admEquipment : content) {
            Map<String, Object> infos = admEquipment.getInfos();
            if(CollUtil.isEmpty(infos)){
                continue;
            }
            for (Map.Entry<String, Object> info : infos.entrySet()) {
                Object value = info.getValue();
                if(deliveredCodes.contains(info.getKey()) || value == null){
                    continue;
                }
                AdmObjectInfo admObjectInfo = admObjectInfoMap.get(info.getKey());
                if(admObjectInfo == null){
                    continue;
                }
                deliveredCodes.add(info.getKey());
                deliveredInfos.add(admObjectInfo);
            }
        }
        return AdmResponse.success(deliveredInfos);
    }

    /**
     * 查询已交付的空间信息点
     * @param context
     * @param request
     */
    private AdmResponse getAdmSpaceDeliveredInfo(InstanceUrlParam context,AdmDictDeliverieInfosRequest request, Map<String, AdmObjectInfo> admObjectInfoMap,List<AdmObjectInfo> deliveredInfos,List<String> deliveredCodes){
        AdmQueryCriteria admQueryCriteria = service.commbineObjectQueryCriteria(request);
        AdmResponse response = spaceService.query(admQueryCriteria);
        List<AdmSpace> content = (List<AdmSpace>)response.getContent();
        if(CollUtil.isEmpty(content)){
            return AdmResponse.success(new ArrayList<>());
        }
        //统计有值的信息点
        for (AdmSpace admSpace : content) {
            Map<String, Object> infos = admSpace.getInfos();
            if(CollUtil.isEmpty(infos)){
                continue;
            }
            for (Map.Entry<String, Object> info : infos.entrySet()) {
                Object value = info.getValue();
                if(deliveredCodes.contains(info.getKey()) || value == null){
                    continue;
                }
                AdmObjectInfo admObjectInfo = admObjectInfoMap.get(info.getKey());
                if(admObjectInfo == null){
                    continue;
                }
                deliveredCodes.add(info.getKey());
                deliveredInfos.add(admObjectInfo);
            }

        }
        return AdmResponse.success(deliveredInfos);
    }

    /**
     * 查询已交付的竖井信息点
     * @param context
     * @param request
     */
    private AdmResponse getAdmShaftDeliveredInfo(InstanceUrlParam context,AdmDictDeliverieInfosRequest request, Map<String, AdmObjectInfo> admObjectInfoMap,List<AdmObjectInfo> deliveredInfos,List<String> deliveredCodes){
        AdmQueryCriteria admQueryCriteria = service.commbineObjectQueryCriteria(request);
        AdmResponse response = shaftService.doQuery(context,admQueryCriteria, AdmShaft.class);
        List<AdmShaft> content = (List<AdmShaft>)response.getContent();
        if(CollUtil.isEmpty(content)){
            return AdmResponse.success(new ArrayList<>());
        }
        //统计有值的信息点
        for (AdmShaft admShaft : content) {
            Map<String, Object> infos = admShaft.getInfos();
            if(CollUtil.isEmpty(infos)){
                continue;
            }
            for (Map.Entry<String, Object> info : infos.entrySet()) {
                Object value = info.getValue();
                if(deliveredCodes.contains(info.getKey()) || value == null){
                    continue;
                }
                AdmObjectInfo admObjectInfo = admObjectInfoMap.get(info.getKey());
                if(admObjectInfo == null){
                    continue;
                }
                deliveredCodes.add(info.getKey());
                deliveredInfos.add(admObjectInfo);
            }

        }
        return AdmResponse.success(deliveredInfos);
    }

    /**
     * 查询已交付的系统信息点
     * @param context
     * @param request
     */
    private AdmResponse getAdmSystemDeliveredInfo(InstanceUrlParam context,AdmDictDeliverieInfosRequest request, Map<String, AdmObjectInfo> admObjectInfoMap,List<AdmObjectInfo> deliveredInfos,List<String> deliveredCodes){
        AdmQueryCriteria admQueryCriteria = service.commbineObjectQueryCriteria(request);
        AdmResponse response = systemService.query(admQueryCriteria);
        List<AdmSystem> content = (List<AdmSystem>)response.getContent();
        if(CollUtil.isEmpty(content)){
            return AdmResponse.success(new ArrayList<>());
        }
        //统计有值的信息点
        for (AdmSystem admSystem : content) {
            Map<String, Object> infos = admSystem.getInfos();
            if(CollUtil.isEmpty(infos)){
                continue;
            }
            for (Map.Entry<String, Object> info : infos.entrySet()) {
                Object value = info.getValue();
                if(deliveredCodes.contains(info.getKey()) || value == null){
                    continue;
                }
                AdmObjectInfo admObjectInfo = admObjectInfoMap.get(info.getKey());
                if(admObjectInfo == null){
                    continue;
                }
                deliveredCodes.add(info.getKey());
                deliveredInfos.add(admObjectInfo);
            }

        }
        return AdmResponse.success(deliveredInfos);
    }

}
