package com.zd.laboratory.service.impl;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.zd.common.core.constant.CacheConstants;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.DateUtils;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.utils.SpringUtils;
import com.zd.common.datascope.annotation.DataScope;
import com.zd.common.redis.service.RedisService;
import com.zd.common.security.utils.SaveUtil;

import com.zd.laboratory.domain.*;
import com.zd.laboratory.domain.vo.*;
import com.zd.laboratory.mapper.*;
import com.zd.laboratory.mqtt.service.impl.SubMessageSendManager;
import com.zd.laboratory.socket.command.Symbol;
import com.zd.laboratory.socket.service.SocketService;
import com.zd.system.api.domain.ParamVo;
import com.zd.system.api.domain.PlayVo;
import com.zd.system.api.speak.RemoteSpeakService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zd.laboratory.service.ILabExitLineService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 逃生线路主Service业务层处理
 *
 * @author zd
 * @date 2022-01-25
 */
@Service
public class LabExitLineServiceImpl implements ILabExitLineService
{
    private final static Logger logger = LoggerFactory.getLogger(LabExitLineServiceImpl.class);
    @Autowired
    private LabExitLineMapper labExitLineMapper;

    @Autowired
    private LabExitLightMapper labExitLightMapper;

    @Autowired
    private LabExitLineJoinMapper labExitLineJoinMapper;

    @Autowired
    private SocketService socketService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SubMessageSendManager messageSendService;
    @Autowired
    private LabSubjectMapper labSubjectMapper;
    @Autowired
    private LabAudioSynthesisMapper labAudioSynthesisMapper;
    @Autowired
    private RemoteSpeakService remoteSpeakService;

    /**
     * 查询逃生线路主
     *
     * @param id 逃生线路主主键
     * @return 逃生线路主
     */
    @Override
    public LabExitLineVO selectLabExitLineById(Long id)
    {
        LabExitLineVO labExitLineVO = labExitLineMapper.selectLabExitLineById(id);
        LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
        labExitLineJoin.setLineId(labExitLineVO.getId());
        List<LabExitLineJoinVO> labExitLineJoinVOList = labExitLineJoinMapper.selectLabExitLineJoinListById(labExitLineJoin);
        labExitLineVO.setLabExitLineJoinList(labExitLineJoinVOList);
        return labExitLineVO;
    }


    /**
     * 查询逃生线路智能指引路线
     *
     * @param subId 实验室主键id
     * @return 逃生线路主
     */
    @Override
    @DataScope(deptAlias = "b", userAlias = "ele", permi = PerPrefix.LABORATORY_LINE)
    public List<LabExitLineJoinVO> selectLabExitLineIntelligentGuidance(Long subId,Integer dire)
    {
        LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
        labExitLineJoin.setSubjectId(subId);
        labExitLineJoin.setLightDirection(dire);
        List<LabExitLineJoinVO> labExitLineJoinVOList = labExitLineJoinMapper.selectLabExitLineIntelligentGuidance(labExitLineJoin);
        //todo 这里临时调用一下处理LightId的办法，以后如果变动，需要重新设计调整，这个方法就不用了。
        changeLightId(labExitLineJoinVOList);
        //验证是否在双向疏散时，都有配置双向线路 如没有 则置空
        if(dire==0){
            boolean leftLight=false,rightLight=false;
            for(LabExitLineJoinVO labExitLineJoinVO:labExitLineJoinVOList){
                if(labExitLineJoinVO.getLightDirection()==1){
                    leftLight = true;
                }
                if(labExitLineJoinVO.getLightDirection()==2){
                    rightLight = true;
                }
            }
            if(!(leftLight && rightLight)){
                labExitLineJoinVOList = Collections.emptyList();
            }
        }
        return labExitLineJoinVOList;
    }


    private void changeLightId(List<LabExitLineJoinVO> labExitLineJoinVOList){
        Optional.ofNullable(labExitLineJoinVOList).orElseGet(Collections::emptyList)
                .stream()
                .forEach(a->{
                    if(a.getLightId().longValue()==7){
                        a.setLightId(1L);
                    }else if(a.getLightId().longValue()==8){
                        a.setLightId(2L);
                    }else if(a.getLightId().longValue()==9){
                        a.setLightId(3L);
                    }else if(a.getLightId().longValue()==10){
                        a.setLightId(4L);
                    }else if(a.getLightId().longValue()==11){
                        a.setLightId(5L);
                    }else if(a.getLightId().longValue()==12){
                        a.setLightId(6L);
                    }
                });

    }

    /**
     * 查询逃生线路主列表
     *
     * @param labExitLine 逃生线路主
     * @return 逃生线路主
     */
    @Override
    @DataScope(deptAlias = "b", userAlias = "el", permi = PerPrefix.LABORATORY_LINE)
    public List<LabExitLineVO> selectLabExitLineList(LabExitLine labExitLine)
    {
        List<LabExitLineVO> labExitLineVOList = labExitLineMapper.selectLabExitLineGroupSubList(labExitLine);

        Optional.ofNullable(labExitLineVOList).orElseGet(Collections::emptyList).stream().forEach(a->{
            LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
            labExitLineJoin.setLineId(a.getId());
            List<LabExitLineJoinVO> labExitLineJoinList = labExitLineJoinMapper.selectLabExitLineJoinListByLight(labExitLineJoin);
            a.setLabExitLineJoinList(labExitLineJoinList);
        });

        return labExitLineVOList;
    }

    /**
     * 新增逃生线路主
     *
     * @param labExitLine 逃生线路主
     * @return 结果
     */
    @Override
    public int insertLabExitLine(LabExitLine labExitLine)
    {
        //设置其他公共字段
        SaveUtil.setCommonAttr(labExitLine);
        return labExitLineMapper.insertLabExitLine(labExitLine);
    }

    /**
     * 新增逃生线路主
     *
     * @param labExitLineVO 逃生线路主
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addExitJoin(LabExitLineVO labExitLineVO)
    {
        LabExitLine labExitLineSql = new LabExitLine();
        labExitLineSql.setBuildId(labExitLineVO.getBuildId());
        labExitLineSql.setLightDirection(labExitLineVO.getLightDirection());
        List<LabExitLine> labExitLineList = labExitLineMapper.selectLabExitLineList(labExitLineSql);
        if(labExitLineList.size()>0){
            LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
            labExitLineJoin.setLightDirection(labExitLineVO.getLightDirection());
            labExitLineJoin.setLineId(labExitLineList.get(0).getId());
//            List<LabExitLineJoin> labExitLineJoinList = labExitLineJoinMapper.selectLabExitLineJoinList(labExitLineJoin);
//            Long[] lightIds = new Long[labExitLineJoinList.size()];
//            for(int i=0;i<labExitLineJoinList.size();i++){
//                lightIds[i] = labExitLineJoinList.get(i).getLightId();
//            }
            //删除指引灯继电器数据
//            labExitLightMapper.deleteLabExitLightByIds(lightIds);
            //删除线路和指引灯关联关系
            labExitLineJoinMapper.deleteLabExitLineJoinByLineId(labExitLineJoin);
            //删除线路数据
            labExitLineMapper.deleteLabExitLineById(labExitLineList.get(0).getId());
        }

        //插入线路主表
        LabExitLine labExitLine = new LabExitLine();
        labExitLine.setLineDeptId(labExitLineVO.getLineDeptId());
        labExitLine.setBuildId(labExitLineVO.getBuildId());
        labExitLine.setLightDirection(labExitLineVO.getLightDirection());
        //设置其他公共字段
        SaveUtil.setCommonAttr(labExitLine);
        labExitLineMapper.insertLabExitLine(labExitLine);
        //插入指引灯数据
        List <LabExitLightVO> labExitLightVOList = labExitLineVO.getLineJoinList();
        Map <String,LabExitLight> checkMap = new HashMap<>();

        //循环遍历指示灯
        for(LabExitLightVO labExitLightVO : labExitLightVOList){
            if(checkMap.get(labExitLightVO.getRelayCode()+""+labExitLightVO.getRelayBit())==null){
                //查询指示灯的列表，需要用继电器编码和几路判断是不是重复数据
                LabExitLight labExitLightOld = new LabExitLight();
                labExitLightOld.setRelayCode(labExitLightVO.getRelayCode());
                labExitLightOld.setRelayBit(labExitLightVO.getRelayBit());
                List<LabExitLight> labExitLights = labExitLightMapper.selectLabExitLightList(labExitLightOld);
                if(labExitLights.size()>0){
                    checkMap.put(labExitLightVO.getRelayCode()+""+labExitLightVO.getRelayBit(),labExitLights.get(0));
                }else{
                    LabExitLight labExitLight = new LabExitLight();
//                labExitLight.setSubjectId(labExitLightVO.getSubjectId());
//                    labExitLight.setBuildId(labExitLineVO.getBuildId());
                    labExitLight.setRelayCode(labExitLightVO.getRelayCode());
                    labExitLight.setRelayBit(labExitLightVO.getRelayBit());
//                labExitLight.setLightDirection(labExitLineVO.getLightDirection());
                    labExitLight.setLightStatus(1);
                    labExitLight.setConfigName(labExitLightVO.getConfigName());
                    labExitLight.setConfigStatus(labExitLightVO.getConfigStatus());
                    //设置其他公共字段
                    SaveUtil.setCommonAttr(labExitLight);
                    labExitLightMapper.insertLabExitLight(labExitLight);
                    checkMap.put(labExitLightVO.getRelayCode()+""+labExitLightVO.getRelayBit(),labExitLight);
                }

            }
        }

        //插入线路和指引灯关联关系
        for(LabExitLightVO labExitLightVO : labExitLightVOList){
            LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
            labExitLineJoin.setLineId(labExitLine.getId());
            labExitLineJoin.setSubjectId(labExitLightVO.getSubjectId());
            labExitLineJoin.setLightId(checkMap.get(labExitLightVO.getRelayCode()+""+labExitLightVO.getRelayBit()).getId());
            labExitLineJoin.setLightOrder(labExitLightVO.getLightOrder());
            labExitLineJoin.setLightDirection(labExitLineVO.getLightDirection());
            //设置其他公共字段
            SaveUtil.setCommonAttr(labExitLineJoin);
            labExitLineJoinMapper.insertLabExitLineJoin(labExitLineJoin);
        }

        return 1;
    }

    /**
     * 修改逃生线路主
     *
     * @param labExitLine 逃生线路主
     * @return 结果
     */
    @Override
    public int updateLabExitLine(LabExitLine labExitLine)
    {
        labExitLine.setUpdateTime(DateUtils.getNowDate());
        labExitLine.setUpdateBy(SecurityUtils.getUsername());
        return labExitLineMapper.updateLabExitLine(labExitLine);
    }

    /**
     * 批量删除逃生线路主
     *
     * @param ids 需要删除的逃生线路主主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteLabExitLineByIds(Long[] ids)
    {
        LabExitLine labExitLineSql = new LabExitLine();
        labExitLineSql.setId(ids[0]);
        List<LabExitLine> labExitLineList = labExitLineMapper.selectLabExitLineList(labExitLineSql);
        if(labExitLineList.size()>0){
            LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
            labExitLineJoin.setLightDirection(labExitLineList.get(0).getLightDirection());
            labExitLineJoin.setLineId(labExitLineList.get(0).getId());
            //删除线路和指引灯关联关系
            labExitLineJoinMapper.deleteLabExitLineJoinByLineId(labExitLineJoin);
            //删除线路数据
            labExitLineMapper.deleteLabExitLineById(labExitLineList.get(0).getId());
        }
        return 1;
    }

    /**
     * 删除逃生线路主信息
     *
     * @param id 逃生线路主主键
     * @return 结果
     */
    @Override
    public int deleteLabExitLineById(Long id)
    {
        return labExitLineMapper.deleteLabExitLineById(id);
    }

    /**
     * 实验室执行应急疏散
     */
    @Override
    public List<LabExitLineJoinVO> doEvacuate(Long subId) {
        return doChange(subId, -1);
    }

    /**
     * 实验室结束应急疏散
     */
    @Override
    public void doClosure(Long subId) {
        redisService.deleteObject(CacheConstants.EVACUATION + subId);
        List<LabExitLineJoinVO> lineJoins = selectLabExitLineIntelligentGuidance(subId, -1);
        if(lineJoins.size() == 0){
            throw new ServiceException("执行疏散未查询到线路！");
        }
        List<LabExitLight> allLines = labExitLightMapper.selectLabExitLightByBuildId(Long.parseLong(lineJoins.get(0).getBuildId()));

        // 关闭该实验室楼层所有指示灯
        for (LabExitLight allLine : allLines) {

            if(StringUtils.isNotBlank(allLine.getRelayCode()) && allLine.getRelayBit() != null){
                if(StringUtils.isBlank(allLine.getConfigName())){
                    logger.error("疏散指示灯调用老继电器");
                    socketService.sendCommand(Symbol.order.control, allLine.getRelayCode(), Symbol.command.close, allLine.getRelayBit());
                }else {
                    logger.error("疏散指示灯调用新继电器");
                    socketService.sendMqttCommand(allLine.getRelayCode(), Symbol.command.close, allLine.getRelayBit()+"");
                }

                logger.info("doClosure 关闭非疏散指示灯：{}，{}，{}", allLine.getRelayCode(), allLine.getRelayBit(), "发送成功");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        //mqtt推送消息
        Map exitLineMap = new HashMap();
        exitLineMap.put("EXIT_LINE_MESSAGE",false);
        messageSendService.SendExitLineUpdate(exitLineMap);

        //todo 关闭喇叭
        try{
            LabAudioSynthesis audioSyntheses = labAudioSynthesisMapper.selectLabAudioSynthesisById(5L);
            if(com.zd.common.core.utils.StringUtils.isNotNull(audioSyntheses)){
                R deviceList = remoteSpeakService.getDeviceList(1,10,5L);
                if(deviceList.getCode()==200){
                    List<Map<String,Object>> mapList = (List <Map <String, Object>>) deviceList.getData();
                    List<PlayVo> playVoList = new ArrayList<>();
                    for(Map<String,Object> map:mapList){
                        logger.info("关闭喇叭日志============================="+map);
                        if(com.zd.common.core.utils.StringUtils.isNotNull(map.get("deviceSn")) && com.zd.common.core.utils.StringUtils.isNotNull(map.get("port"))){
                            PlayVo playVo = new PlayVo();
                            playVo.setSn(map.get("deviceSn")+"");
                            playVo.setPort(Integer.parseInt(map.get("port")+""));
                            ParamVo paramVo=new ParamVo();
                            playVo.setParams(paramVo);
                            playVoList.add(playVo);
                            remoteSpeakService.stopPlayMusic(map.get("deviceSn")+"",audioSyntheses.getNewMusicUrl());

                        }
                    }

                }
            }
        }catch (Exception e){
            logger.error("开启喇叭失败！！！！！:"+e);
        }
    }

    /**
     * 实验室切换应急疏散线路
     * @param type 1是向左疏散，2是向右疏散，0是两侧疏散
     */
    @Override
    public List<LabExitLineJoinVO> doChange(Long subId, Integer type) {

        if(redisService.hasKey(CacheConstants.EVACUATION + subId)){
            EvacuationLine evacuationLine = redisService.getCacheObject(CacheConstants.EVACUATION + subId);
            if(type.equals(evacuationLine.getType())){
                //如果相等 取redis的值，不相等就要后续取查
                return evacuationLine.getLineJoins();
                // -1 直接取redis的值
            }else if(type==-1){
                return evacuationLine.getLineJoins();
            }
        }

        //手动变更疏散线路的时候，如果向左，左侧灯全部亮，向右，右侧灯全部亮，如果两侧，需要查询起始等是否具备两侧疏散
        List<LabExitLineJoinVO> lineJoins;
        if(type==0){
            lineJoins = selectLabExitLineIntelligentGuidance(subId, type);
            if(lineJoins.size() == 0){
                throw new ServiceException("执行疏散未查询到线路！");
            }
        }else{
            LabExitLineJoin labExitLineJoin = new LabExitLineJoin();
            labExitLineJoin.setLightDirection(type);
            lineJoins = labExitLineJoinMapper.selectLabExitFloorAllLine(labExitLineJoin);
            if(lineJoins.size() == 0){
                throw new ServiceException("执行疏散未查询到线路！");
            }
//            LabExitLight labExitLight = new LabExitLight();
//            labExitLight.setLightDirection(type);
//            List<LabExitLight> exitLightList = labExitLightMapper.selectLabExitLightList(labExitLight);
//            for(LabExitLight exitLight:exitLightList){
//                LabExitLineJoinVO joinVO = new LabExitLineJoinVO();
//                joinVO.setLightId(exitLight.getId());
//                joinVO.setRelayCode(exitLight.getRelayCode());
//                joinVO.setRelayBit(exitLight.getRelayBit()+"");
//
//                lineJoins.add(joinVO);
//            }
        }


//        List<LabExitLineJoinVO> lineJoins = selectLabExitLineIntelligentGuidance(subId, type);
//        if(lineJoins.size() == 0){
//            throw new ServiceException("执行疏散未查询到线路！");
//        }


        // 根据楼层查询指示灯
//        List<LabExitLight> allLines = labExitLightMapper.selectLabExitLightByBuildId(Long.parseLong(lineJoins.get(0).getBuildId()));
        List<LabExitLight> allLines = labExitLightMapper.selectLabExitLightList(new LabExitLight());


        for (int i = 0; i < allLines.size(); i++) {
            for (LabExitLineJoinVO lineJoin : lineJoins) {
                if(lineJoin.getLightId().equals(allLines.get(i).getId())){
                    allLines.remove(i);
                    i--;
                    break;
                }
            }
        }

        // 先关闭不是疏散的指示灯
        for (LabExitLight allLine : allLines) {
            if(StringUtils.isNotBlank(allLine.getRelayCode()) && allLine.getRelayBit() != null){

                if(StringUtils.isBlank(allLine.getConfigName())){
                    logger.error("疏散指示灯调用老继电器");
                    socketService.sendCommand(Symbol.order.control, allLine.getRelayCode(), Symbol.command.close, allLine.getRelayBit());
                }else {
                    logger.error("疏散指示灯调用新继电器");
                    socketService.sendMqttCommand(allLine.getRelayCode(), Symbol.command.close, allLine.getRelayBit()+"");
                }
                logger.info("关闭非疏散指示灯：{}，{}，{}", allLine.getRelayCode(), allLine.getRelayBit(), "发送成功");

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        // 再打开疏散指示灯
        for (LabExitLineJoinVO lineJoin : lineJoins) {
            if(StringUtils.isNotBlank(lineJoin.getRelayCode()) && StringUtils.isNotBlank(lineJoin.getRelayBit())){

                if(StringUtils.isBlank(lineJoin.getConfigName())){
                    logger.error("疏散指示灯调用老继电器");
                    socketService.sendCommand(Symbol.order.control, lineJoin.getRelayCode(), Symbol.command.open, Integer.parseInt(lineJoin.getRelayBit()));
                }else {
                    logger.error("疏散指示灯调用新继电器");
                    socketService.sendMqttCommand(lineJoin.getRelayCode(), Symbol.command.open, lineJoin.getRelayBit());
                }

                logger.info("打开疏散指示灯：{}，{}，{}", lineJoin.getRelayCode(), lineJoin.getRelayBit(), "发送成功");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        EvacuationLine evacuationLine = new EvacuationLine();
        evacuationLine.setType(type);
        evacuationLine.setLineJoins(lineJoins);

        redisService.setCacheObject(CacheConstants.EVACUATION + subId, evacuationLine,1L, TimeUnit.DAYS);
        //mqtt推送消息
        Map exitLineMap = new HashMap();
        exitLineMap.put("EXIT_LINE_MESSAGE",true);
        messageSendService.SendExitLineUpdate(exitLineMap);

        //todo 这里先写死一个喇叭播报，如果后期需要改动，在重新调整。
        //这里查询预案下的合成音乐
        if(redisService.getCacheObject("subjectByExit"+subId)==null){
            try{
                LabAudioSynthesis audioSyntheses = labAudioSynthesisMapper.selectLabAudioSynthesisById(5L);
                if(com.zd.common.core.utils.StringUtils.isNotNull(audioSyntheses)){
                    //获取喇叭列表
                    R deviceList = remoteSpeakService.getDeviceList(1,10, 5L);
                    if(deviceList.getCode()==200){
                        List<Map<String,Object>> mapList = (List <Map <String, Object>>) deviceList.getData();

                        for(Map<String,Object> map:mapList){
                            logger.info("喇叭日志============================="+map);
                            if(com.zd.common.core.utils.StringUtils.isNotNull(map.get("deviceSn")) && com.zd.common.core.utils.StringUtils.isNotNull(map.get("port"))){
                                List<PlayVo> playVoList = new ArrayList<>();
                                PlayVo playVo = new PlayVo();
                                playVo.setSn(map.get("deviceSn")+"");
                                playVo.setDeviceIp(map.get("deviceIp")+"");
                                playVo.setPort(Integer.parseInt(map.get("port")+""));
                                ParamVo paramVo=new ParamVo();
                                playVo.setParams(paramVo);
                                playVoList.add(playVo);
                                remoteSpeakService.textParseUrlAppIps(audioSyntheses.getNewMusicUrl(),playVoList);
                            }
                        }

                    }
                }
            }catch (Exception e){
                logger.error("开启喇叭失败！！！！！:"+e);
            }
        }

        return lineJoins;
    }

    /**
     * 获取逃生线路缓存数据
     */
    @Override
    public EvacuationLine getRedis(){
        Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.EVACUATION + "*");
        for(String key:keys){
            EvacuationLine evacuationLine = redisService.getCacheObject(key);
            String keyLength = key.substring(key.indexOf(":")+1);
            evacuationLine.setSubId(keyLength);
            LabSubjectVO labSubject = labSubjectMapper.selectLabSubjectVoById(Long.parseLong(keyLength));
            evacuationLine.setDeptId(labSubject.getDeptId());
            evacuationLine.setDeptName(labSubject.getDeptName());
            evacuationLine.setFloorId(labSubject.getFloorId());
            evacuationLine.setSubName(labSubject.getName());
            evacuationLine.setBuildId(labSubject.getBuildId());
            evacuationLine.setBuildName(labSubject.getBuildName());
            evacuationLine.setFloorName(labSubject.getFloorName());
            return evacuationLine;
        }
        return null;
    }

    @Override
    public List<LabExitLineJoinVO> getRoute(Long subId, Integer type) {
        List<LabExitLineJoinVO> lineJoins = selectLabExitLineIntelligentGuidance(subId, type);
        if(lineJoins.size() == 0){
            throw new ServiceException("未查询到疏散线路！");
        }
        return lineJoins;
    }
}
