package com.zd.laboratory.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.enums.WarnUserAttrEnum;
import com.zd.common.core.utils.DateUtils;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.datascope.annotation.DataScope;
import com.zd.common.security.utils.SaveUtil;
import com.zd.laboratory.domain.LabRiskPlan;
import com.zd.laboratory.domain.LabSubject;
import com.zd.laboratory.domain.dto.LabMessageContentDTO;
import com.zd.laboratory.domain.dto.LabMessageContentListQuery;
import com.zd.laboratory.domain.vo.LabMessageContentVO;
import com.zd.laboratory.domain.vo.LabSubjectAccessRecordVo;
import com.zd.laboratory.domain.vo.LabSubjectVO;
import com.zd.laboratory.mapper.LabContentMachineMsgMapper;
import com.zd.laboratory.mapper.LabMessageContentMapper;
import com.zd.laboratory.mapper.LabSubjectMapper;
import com.zd.laboratory.mqtt.constants.MqttConstants;
import com.zd.laboratory.mqtt.entiy.MessageBody;
import com.zd.laboratory.mqtt.enums.SendMode;
import com.zd.laboratory.mqtt.service.impl.CommonSend;
import com.zd.laboratory.service.*;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.alarm.RemoteAlarmService;
import com.zd.system.api.alarm.domain.AlarmEntrty;
import com.zd.system.api.alarm.domain.Routes;
import com.zd.system.api.chemical.RemoteStockService;
import com.zd.system.api.laboratory.domain.LabMessageContent;
import com.zd.system.api.laboratory.domain.SubAddrr;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 消息发布Service业务层处理
 *
 * @author zd
 * @date 2021-09-02
 */
@Service
public class LabMessageContentServiceImpl implements ILabMessageContentService {
    Logger logger = LoggerFactory.getLogger(LabMessageContentServiceImpl.class);

    @Autowired
    private LabMessageContentMapper labMessageContentMapper;

    @Autowired
    private ILabSubjectLayoutService subjectLayoutService;

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    private LabSubjectMapper labSubjectMapper;
    @Autowired
    private ILabSubjectAccessRecordService subjectAccessRecordService;

    @Autowired
    ILabWarnPushMessageService labWarnPushMessageService;

    @Autowired
    RemoteAlarmService remoteAlarmService;

    @Autowired
    CommonSend commonSend;
    @Autowired
    private ILabContentMachineMsgService labContentMachineMsgService;
    @Autowired
    private LabContentMachineMsgMapper labContentMachineMsgMapper;

    public Integer phoneMode;

    @Value("${phoneMode:0}")
    private void setPhoneMode(Integer phoneMode){
        this.phoneMode = phoneMode;
    }

    @Autowired
    RemoteStockService remoteStockService;


    private final String smsFormat="{}: {}，发生风险预案,{}";
    /**
     * 查询消息发布
     *
     * @param id 消息发布主键
     * @return 消息发布
     */
    @Override
    public LabMessageContent selectLabMessageContentById(Long id) {
        return labMessageContentMapper.selectLabMessageContentById(id);
    }


    /**
     * 查询消息发布列表
     *
     * @param labMessageContent 消息发布
     * @return 消息发布
     */
    @Override
    public List<LabMessageContent> selectLabMessageContentList(LabMessageContent labMessageContent) {
        return labMessageContentMapper.selectLabMessageContentList(labMessageContent);
    }


    /**
     * 查询消息发布列表
     *
     * @param labMessageContent 消息发布
     * @return 消息发布
     */
    @Override
    @DataScope(deptAlias = "s" , permi = PerPrefix.LABORATORY_CONTENT)
    public List<LabMessageContentVO> selectLabMessageContentVOList(LabMessageContentListQuery labMessageContent) {
        return labMessageContentMapper.selectLabMessageContentVOList(labMessageContent);
    }


    /**
     * 新的发送消息
     * 相较之前的功能修改入如下：
     * ①全院，院系和个人不再给用户单独发送
     * 坏处：1，查询复杂，逻辑不统一，2.新建的用户能看到全校和所属院系历史所有数据（可以增加时间过滤来解决，暂时不解决） ，3 用户院系发生变化，时能看到之前该院系消息（该方式无解）
     * 好处：一次只产生一条消息，能极大的减少负载。
     * @param labMessageContent
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean sendMessage(LabMessageContent labMessageContent) {
        //消息表入库
        if(labMessageContent.getMessClass() == null){
            labMessageContent.setMessClass(1);
        }

        insertLabMessageContent(labMessageContent);

        if(labMessageContent.getMessClass() == 3 && StringUtils.isNotBlank(labMessageContent.getSubIds())){
            // 一体机消息发送mqtt 通知，并生成相关数据
            labContentMachineMsgService.insert(labMessageContent);
        }
        return true;
    }

    private Boolean sendMessageWarn(LabMessageContentDTO labMessageContentDTO) {
        LabMessageContent labMessageContent = new LabMessageContent();
        BeanUtils.copyProperties(labMessageContentDTO, labMessageContent);
        //消息表入库
        labMessageContent.setMessClass(2);
        insertLabMessageContent(labMessageContent);
        return true;
    }

    /**
     * 发送预警消息
     * 这里一定要重构，预警消息里内部又发送预案消息，以后需要重构为事件驱动
     *
     *
     * @param subId 实验室ID
     * @param newRiskPlan 预案
     */
    @Async("labExecutor")
    public void  sendWranMessage(Long subId, LabRiskPlan newRiskPlan,Long groupId)
    {
        logger.info("*******************sendWranMessage***********************");
        //获取实验室负责人信息
        LabSubject subject = new LabSubject();
        subject.setId(subId);
        List<LabSubjectVO> labSubjects = labSubjectMapper.selectLabSubjectVOList(subject);
        logger.info("**************labSubjects.size()***********"+labSubjects.size());
        Optional.ofNullable(labSubjects)
                .filter(a -> a.size() > 0)
                .map(a -> a.get(0))
                .map(a->{
                    sendSubWran(a,newRiskPlan,groupId);
                    return a;
                })
                .orElse(null);
    }

    private void  sendSubWran(LabSubjectVO subject,LabRiskPlan newRiskPlan,Long groupId)
    {
        logger.info("$$$$$$$$$$$$$进入sendSubWran$$$$$$$$$$$$$");
        String safeUserId=subject.getSafeUserId();
        if(StringUtils.isNotBlank(safeUserId)){
            subject.setSafeUserPhone(labSubjectMapper.queryUserPhoneBySafeUserId(safeUserId));
        }
        String deptName = "";
        List<SubAddrr> subAddrrs = subjectLayoutService.selectAddrrByLayoutIds(subject.getLayoutId());
        if(CollectionUtils.isNotEmpty(subAddrrs) && subAddrrs.size() > 0){
            deptName = subAddrrs.get(0).getBuildName();
        }

        String format = StrUtil.format(smsFormat, deptName, subject.getName(), StrUtil.isBlank(newRiskPlan.getMessage()) ? newRiskPlan.getName() : newRiskPlan.getMessage());
        String phone =null;
        String userids = null;
        try {
            userids = getDoingUserId(subject);
            if(StrUtil.isNotBlank(userids))
            {

                R<List<String>> phoneByUserIDS = remoteUserService.getPhoneByUserIDS(userids);
                if(phoneByUserIDS.getCode()==200&& CollUtil.isNotEmpty(phoneByUserIDS.getData()))
                {
                    phone = phoneByUserIDS.getData().stream()
                            .collect(Collectors.joining(","));

                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("获取实验室内部短信发送人出错");
        }
        String[] strings = Stream.of(new String[]{subject.getAdminPhone(), subject.getSafeUserPhone(), phone})
                .filter(a -> StrUtil.isNotBlank(a))
                .collect(Collectors.joining(","))
                .split(",");

        logger.info("%%%%%%%%%%%%%%%%%%%%strings:"+strings);
        //todo 发送最多支持200个电话号码 ， 这里不会超过200人 所以没有验证， 切割
        //todo 这里判断电话类型，如果是0，发送短信，如果是1,是四医大内部短信接口。
        if(phoneMode == 0){
            if(strings!=null)
            {
                AlarmEntrty alarmEntrty = new AlarmEntrty(Routes.NoticePush,strings,format);
                MessageBody messageBody = new MessageBody();
                messageBody.setData(alarmEntrty);
                commonSend.send("alarm/"+newRiskPlan.getId()+"/"+subject.getId(),messageBody, SendMode.DISTINCT);
                logger.info("&&&&"+"alarm/"+newRiskPlan.getId()+"/"+subject.getId());
                logger.info("&&&&"+JSON.toJSONString(messageBody));
//           改用mqtt
//           AjaxResult send = remoteAlarmService.send(alarmEntrty);
                try {
                    if(subject.getAdminId()!=null)
                    {
                        //发送预案消息（预案指挥中心） 没什么卵用 lab_warn_push_message
                        labWarnPushMessageService.insertLabWarnPushMessage(subject.getId(),subject.getAdminId().toString(),groupId,newRiskPlan, WarnUserAttrEnum.ADMIN);
                    }
                    //发送预案消息（预案指挥中心） 没什么卵用 lab_warn_push_message 保持实验室内部人员发送记录  ？安全的要不要保存展示？
                    labWarnPushMessageService.insertLabWarnPushMessage(subject.getId(),userids,groupId,newRiskPlan, WarnUserAttrEnum.NONE);
                } catch (Exception e) {
                    logger.error("发送预案消息失败！");
                }
            }

            //发送消息
            if(StrUtil.isNotBlank(newRiskPlan.getInformation()))
            {
                String collect = Stream.of(new String[]{subject.getAdminId()==null?null:subject.getAdminId().toString(), subject.getSafeUserId()})
                        .filter(a -> StrUtil.isNotBlank(a))
                        .collect(Collectors.joining(","));
                if(StrUtil.isNotBlank(collect))
                {
                    LabMessageContentDTO labMessageContentDTO = new LabMessageContentDTO();
                    labMessageContentDTO.setUserIds(collect);
                    labMessageContentDTO.setSendMode(2);
                    labMessageContentDTO.setSendRange(3);
                    labMessageContentDTO.setContent(newRiskPlan.getMessage());
                    labMessageContentDTO.setUserId(-2L);
                    sendMessageWarn(labMessageContentDTO);
                }

            }
        }else if(phoneMode == 1){
            //走四医大发送短信服务接口
            remoteStockService.sendSydSms(newRiskPlan.getMessage(),5,null,strings);
        }

    }

    private String getDoingUserId(LabSubjectVO subject) {
        LabSubjectAccessRecordVo labSubjectAccessRecordVo;
        labSubjectAccessRecordVo = new LabSubjectAccessRecordVo();
        labSubjectAccessRecordVo.setAccessStatus(1l);
        labSubjectAccessRecordVo.setSubjectId(subject.getId());
        labSubjectAccessRecordVo.setInitFlag(false);
        List<LabSubjectAccessRecordVo> labSubjectAccessRecordVos = subjectAccessRecordService.selectLabSubjectAccessRecordListNoAuth(labSubjectAccessRecordVo);
        //userids
        String userids = Optional.ofNullable(labSubjectAccessRecordVos)
                        .filter(a->a.size()>0)
                                .orElse(Collections.emptyList())
                                .stream().map(a->a.getJoinUserId()).filter(a->a!=null)
                .map(a->a.toString())
                        .collect(Collectors.joining(","));
        return userids;
    }



    /**
     * 新增消息发布
     *
     * @param labMessageContent 消息发布
     * @return 结果
     */
    @Override
    public int insertLabMessageContent(LabMessageContent labMessageContent) {
        //设置其他公共字段
        logger.info("***************SaveUtil.setCommonAttr开始*****************");
        try {
            SaveUtil.setCommonAttr(labMessageContent);
        }catch (Exception e){
            logger.info("异常了："+e.getMessage());
        }
        logger.info("***************SaveUtil.setCommonAttr结束*****************");
        return labMessageContentMapper.insertLabMessageContent(labMessageContent);
    }

    /**
     * 修改消息发布
     *
     * @param labMessageContent 消息发布
     * @return 结果
     */
    @Override
    public int updateLabMessageContent(LabMessageContent labMessageContent) {
        labMessageContent.setUpdateTime(DateUtils.getNowDate());
        labMessageContent.setUpdateBy(SecurityUtils.getUsername());
        return labMessageContentMapper.updateLabMessageContent(labMessageContent);
    }

    /**
     * 批量删除消息发布
     *
     * @param ids 需要删除的消息发布主键
     * @return 结果
     */
    @Override
    public int deleteLabMessageContentByIds(Long[] ids) {
        return labMessageContentMapper.deleteLabMessageContentByIds(ids);
    }

    /**
     * 删除消息发布信息
     *
     * @param id 消息发布主键
     * @return 结果
     */
    @Override
    public int deleteLabMessageContentById(Long id) {
        return labMessageContentMapper.deleteLabMessageContentById(id);
    }


    /**
     * 查询预案向一体机推送的消息，如果超过两小时，需要清理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int outTimeClearMessage() {
        int flag = 1;
        LabMessageContentListQuery labMessageContentListQuery = new LabMessageContentListQuery();
        labMessageContentListQuery.setSendRange(4);
        labMessageContentListQuery.setMessClass(3);
        List<LabMessageContentVO> labMessageContentList = labMessageContentMapper.selectLabClearMessageList(labMessageContentListQuery);
        Optional.ofNullable(labMessageContentList).orElseGet(Collections::emptyList).stream()
                .forEach(a->{
                    labContentMachineMsgMapper.deleteLabContentMachineMsgByContentId(a.getId());
                    labMessageContentMapper.deleteLabMessageContentById(a.getId());
                    // 生成一条通知一个，此处不应该有重复的实验室ID
                    commonSend.send(MqttConstants.LAB_CONTENT + a.getSubIds(), "收到一条新的消息通知！");
                });
        return flag;
    }
}
