package com.xinelu.quartz.service.impl;

import com.xinelu.common.config.PushMessageRestrictions;
import com.xinelu.common.config.WeChatAppletChatConfig;
import com.xinelu.common.enums.ErrorStatusEnum;
import com.xinelu.common.enums.NodeExecuteResultStatusEnum;
import com.xinelu.common.enums.NodeExecuteStatusEnum;
import com.xinelu.common.enums.RouteNodeNameEnum;
import com.xinelu.common.enums.SubscribeStatusEnum;
import com.xinelu.manage.domain.subscribemessagesendrecord.SubscribeMessageSendRecord;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
import com.xinelu.manage.mapper.subscribemessagesendrecord.SubscribeMessageSendRecordMapper;
import com.xinelu.manage.service.patienttaskstatistics.IPatientTaskStatisticsService;
import com.xinelu.manage.vo.subscribemessagesendrecord.RecordNum;
import com.xinelu.mobile.mapper.homepage.HomePageMapper;
import com.xinelu.mobile.utils.WeChatOfficialAccountUtils;
import com.xinelu.mobile.vo.wechatofficialaccountcallback.PatientVO;
import com.xinelu.quartz.service.SubscribeTaskService;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

/**
 * @Description 消息推送定时任务业务层
 * @Author zh
 * @Date 2024-05-24
 */
@Service
@Slf4j
public class subscribeTaskServiceImpl implements SubscribeTaskService {

    @Resource
    private HomePageMapper homePageMapper;
    @Resource
    private WeChatAppletChatConfig weChatAppletChatConfig;
    @Resource
    private WeChatOfficialAccountUtils weChatOfficialAccountUtils;
    @Resource
    private SubscribeMessageSendRecordMapper subscribeMessageSendRecordMapper;
    @Resource
    private PushMessageRestrictions pushMessageRestrictions;
    @Resource
    private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;
	@Resource
	private IPatientTaskStatisticsService patientTaskStatisticsService;

    /**
     * 推送任务组装数据
     */
    public void signPatientManageRouteNodeTask() {
        //微信小程序订阅消息记录表
        //1、获取已订阅 指定  小程序通知模版 的 患者列表；
        List<PatientVO> patientList = homePageMapper.selectResidentAndSubscribeMessageRecord(SubscribeStatusEnum.accept.getValue(), weChatAppletChatConfig.getHealthyPropagandaId());
       //1.1 获取已订阅 指定  小程序通知模版 的 患者ID列表；
        List<Long> patientIdList = patientList.stream().filter(Objects::nonNull).map(PatientVO::getPatientId).filter(Objects::nonNull).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(patientIdList)) {
            return;
        }
        // 2、患者节点表（患者任务表）
        List<PatientVO> signPatientManageRouteNodes = homePageMapper.selectSignPatientManageRouteNode(patientIdList);
        if (CollectionUtils.isEmpty(signPatientManageRouteNodes)) {
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        // 注：PatientVO 包含签约路径节点相关属性，后面用于推送消息
        List<PatientVO> patientVOList = new ArrayList<>();
        //发送消息到期节点id集合
        List<Long> expiredManageRouteNodeIds = new ArrayList<>();
        //2.1 开始遍历患者任务,组装数据
        for (PatientVO signPatientManageRouteNode : signPatientManageRouteNodes) {
            //判断推送状态
            if (Objects.isNull(signPatientManageRouteNode.getAppletPushSign()) || signPatientManageRouteNode.getAppletPushSign() != 1) {
                continue;
            }
            //判断路径节点，组装数据
            LocalDate localDate = null;
            PatientVO patientVO = patientList.stream().filter(Objects::nonNull).filter(item -> signPatientManageRouteNode.getPatientId().equals(item.getPatientId())).findFirst().orElse(new PatientVO());
            if (Objects.nonNull(patientVO.getDischargeTime())) {
                localDate = patientVO.getDischargeTime().plusDays(signPatientManageRouteNode.getRouteNodeDay());
            }
            if (Objects.isNull(patientVO.getDischargeTime()) && Objects.nonNull(patientVO.getVisitDate())) {
                localDate = patientVO.getVisitDate().plusDays(signPatientManageRouteNode.getRouteNodeDay());
            }
            if (Objects.isNull(localDate)) {
                continue;
            }
            boolean before = localDate.isBefore(LocalDate.now()) || localDate.isEqual(LocalDate.now());
            if (before) {
                long until = localDate.until(LocalDate.now(), ChronoUnit.DAYS);
                //已过期 任务
                if (until >= pushMessageRestrictions.getTime()) {
                    expiredManageRouteNodeIds.add(signPatientManageRouteNode.getSignPatientManageRouteNodeId());
                    continue;
                }
                signPatientManageRouteNode.setOpenId(patientVO.getOpenId());
                //转换成中文……
                signPatientManageRouteNode.setRouteNodeName(RouteNodeNameEnum.getNameByInfo(signPatientManageRouteNode.getRouteNodeName()).getName());
                //待发送 任务列表
                patientVOList.add(signPatientManageRouteNode);
            }
        }
        //2.2 对过期的任务，更改过期执行状态
        if (CollectionUtils.isNotEmpty(expiredManageRouteNodeIds)) {
            signPatientManageRouteNodeMapper.updateNodeExecuteStatusByIds(expiredManageRouteNodeIds, NodeExecuteStatusEnum.EXECUTED.getInfo(), NodeExecuteResultStatusEnum.EXPIRED.getInfo(), null, null, now);
        }

//            //如果节点 适用范围是 出院后或就诊/出院后
//            if (signPatientManageRouteNode.getRouteNodeName().equals(RouteNodeNameEnum.AFTER_DISCHARGE.getInfo()) || signPatientManageRouteNode.getRouteNodeName().equals(RouteNodeNameEnum.AFTER_VISIT_DISCHARGE.getInfo())) {
//                PatientVO patientVO = patientList.stream().filter(Objects::nonNull).filter(item -> signPatientManageRouteNode.getPatientId().equals(item.getPatientId())).findFirst().orElse(new PatientVO());
//                //患者类型如果是 出院患者
//                if (patientVO.getPatientType().equals(PatientTypeEnum.DISCHARGED_PATIENT.getInfo())) {
//                    //出院时间
//                    LocalDate localDate = patientVO.getDischargeTime().plusDays(signPatientManageRouteNode.getRouteNodeDay());
//                    boolean before = localDate.isBefore(LocalDate.now()) || localDate.isEqual(LocalDate.now());
//                    if (before) {
//                        signPatientManageRouteNode.setOpenId(patientVO.getOpenId());
//                        signPatientManageRouteNode.setRouteNodeName(RouteNodeNameEnum.AFTER_DISCHARGE.getName());
//                        patientVOList.add(signPatientManageRouteNode);
//                    }
//                }
//            }
//            //如果节点适用范围是 入院后
//            if (signPatientManageRouteNode.getRouteNodeName().equals(RouteNodeNameEnum.AFTER_ADMISSION.getInfo())) {
//                PatientVO patientVO = patientList.stream().filter(Objects::nonNull).filter(item -> signPatientManageRouteNode.getPatientId().equals(item.getPatientId())).findFirst().orElse(new PatientVO());
//                //患者类型如果是 在院患者
//                if (patientVO.getPatientType().equals(PatientTypeEnum.IN_HOSPITAL_PATIENT.getInfo())) {
//                if (patientVO.getPatientType().equals(PatientTypeEnum.IN_HOSPITAL_PATIENT.getInfo())) {
//                    //入院时间
//                    LocalDate localDate = patientVO.getAdmissionTime().plusDays(signPatientManageRouteNode.getRouteNodeDay());
//                    boolean before = localDate.isBefore(LocalDate.now()) || localDate.isEqual(LocalDate.now());
//                    if (before) {
//                        signPatientManageRouteNode.setOpenId(patientVO.getOpenId());
//                        signPatientManageRouteNode.setRouteNodeName(RouteNodeNameEnum.AFTER_ADMISSION.getName());
//                        patientVOList.add(signPatientManageRouteNode);
//                    }
//                }
//            }
//            //如果节点 适用范围是 就诊后 或 就诊/出院后
//            if (signPatientManageRouteNode.getRouteNodeName().equals(RouteNodeNameEnum.AFTER_CONSULTATION.getInfo()) || signPatientManageRouteNode.getRouteNodeName().equals(RouteNodeNameEnum.AFTER_VISIT_DISCHARGE.getInfo())) {
//                PatientVO patientVO = patientList.stream().filter(Objects::nonNull).filter(item -> signPatientManageRouteNode.getPatientId().equals(item.getPatientId())).findFirst().orElse(new PatientVO());
//                //患者类型如果是 门诊患者
//                if (patientVO.getPatientType().equals(PatientTypeEnum.OUTPATIENT.getInfo()) && patientVO.getAdmissionTime() == null) {
//                    //就诊时间
//                    LocalDate localDate = patientVO.getVisitDate().plusDays(signPatientManageRouteNode.getRouteNodeDay());
//                    boolean before = localDate.isBefore(LocalDate.now()) || localDate.isEqual(LocalDate.now());
//                    if (before) {
//                        signPatientManageRouteNode.setOpenId(patientVO.getOpenId());
//                        signPatientManageRouteNode.setRouteNodeName(RouteNodeNameEnum.AFTER_CONSULTATION.getName());
//                        patientVOList.add(signPatientManageRouteNode);
//                    }
//                }
//            }
        if (CollectionUtils.isEmpty(patientVOList)) {
            return;
        }
        //2.3 节点推送数量，用于判断失败次数，若达到最大值，则认为失败；
        List<Long> collect = patientVOList.stream().filter(Objects::nonNull).map(PatientVO::getSignPatientManageRouteNodeId)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        //RecordNum，manageRouteNodeId：任务ID，num：已推送次数
        List<RecordNum> recordNums = subscribeMessageSendRecordMapper.selectRecordCountByManageRouteNodeIds(collect);
        //发送成功id集合
        List<Long> signPatientManageRouteNodeIds = new ArrayList<>();
        //发送失败
        List<Long> failSignPatientManageRouteNodeIds = new ArrayList<>();
	    Set<Long> patientIdSet = new HashSet<>();

        //3、----------开始推送------------//
        for (PatientVO patientVO : patientVOList) {
            // 开始推送消息
            Integer integer = weChatOfficialAccountUtils.sendAppletTemplateMessage(patientVO);
            SubscribeMessageSendRecord subscribeMessageSendRecord = new SubscribeMessageSendRecord();
            //推送结果
            if (integer == 0) {
                signPatientManageRouteNodeIds.add(patientVO.getSignPatientManageRouteNodeId());
                subscribeMessageSendRecord.setErrorCode(0);
                subscribeMessageSendRecord.setErrorStatus(ErrorStatusEnum.success.getValue());
				// 修改患者任务统计表
	            patientIdSet.add(patientVO.getPatientId());
            } else {
                subscribeMessageSendRecord.setErrorCode(integer);
                subscribeMessageSendRecord.setErrorStatus(ErrorStatusEnum.fail.getValue());
                RecordNum recordNum = recordNums.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getManageRouteNodeId()) && item.getManageRouteNodeId().equals(patientVO.getSignPatientManageRouteNodeId())).findFirst().orElse(new RecordNum());
                //若已推送次数达到 配置的 最大次数，则认为：失败；
                if (Objects.nonNull(recordNum.getNum()) && recordNum.getNum() >= pushMessageRestrictions.getNumber()) {
                    failSignPatientManageRouteNodeIds.add(patientVO.getSignPatientManageRouteNodeId());
                }
            }
            subscribeMessageSendRecord.setPatientId(patientVO.getPatientId());
            subscribeMessageSendRecord.setManageRouteNodeId(patientVO.getSignPatientManageRouteNodeId());
            subscribeMessageSendRecord.setSubscribeTime(LocalDateTime.now());
            subscribeMessageSendRecord.setOpenid(patientVO.getOpenId());
            subscribeMessageSendRecord.setAppletId(weChatAppletChatConfig.getAppletId());
            subscribeMessageSendRecord.setTemplateId(weChatAppletChatConfig.getHealthyPropagandaId());
            subscribeMessageSendRecord.setCreateTime(LocalDateTime.now());
            //3.1 托送记录入库
            subscribeMessageSendRecordMapper.insertSubscribeMessageSendRecord(subscribeMessageSendRecord);
        }
        //4、更改成功执行状态
        if (CollectionUtils.isNotEmpty(signPatientManageRouteNodeIds)) {
            signPatientManageRouteNodeMapper.updateNodeExecuteStatusByIds(signPatientManageRouteNodeIds, NodeExecuteStatusEnum.EXECUTED.getInfo(), NodeExecuteResultStatusEnum.SUCCESS.getInfo(), null, null,now);
        }
        //4.2 更改失败执行状态
        if (CollectionUtils.isNotEmpty(failSignPatientManageRouteNodeIds)) {
            signPatientManageRouteNodeMapper.updateNodeExecuteStatusByIds(failSignPatientManageRouteNodeIds, NodeExecuteStatusEnum.EXECUTED.getInfo(), NodeExecuteResultStatusEnum.FAILURE.getInfo(), null, null,now);
        }
	    //5、 患者任务统计表修改
	    if (CollectionUtils.isNotEmpty(patientIdSet)) {
		    patientTaskStatisticsService.updateNum(new ArrayList<>(patientIdSet));
	    }
    }
}
