package com.reyun.saas.mob.user.thread.warning;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.reyun.saas.common.properties.CommonProperties;
import com.reyun.saas.common.util.SpringContextUtil;
import com.reyun.saas.mob.user.dao.AppMapper;
import com.reyun.saas.mob.user.dao.WarningAddresseeMapper;
import com.reyun.saas.mob.user.dao.WarningDataInfoMapper;
import com.reyun.saas.mob.user.dao.WarningInformLogMapper;
import com.reyun.saas.mob.user.domain.App;
import com.reyun.saas.mob.user.domain.WarningAddressee;
import com.reyun.saas.mob.user.domain.WarningDataInfo;
import com.reyun.saas.mob.user.domain.WarningInformLog;
import com.reyun.saas.mob.user.dto.WarningConfigDTO;
import com.reyun.saas.mob.util.SendCloudComponent;
import com.reyun.saas.report.data.dao.WarningReportMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @desc
 */
@Slf4j
public class WarningThread implements Runnable {
    private WarningAddresseeMapper warningAddresseeMapper = SpringContextUtil.getBean(WarningAddresseeMapper.class);
    private WarningDataInfoMapper warningDataInfoMapper = SpringContextUtil.getBean(WarningDataInfoMapper.class);
    private WarningReportMapper warningReportMapper = SpringContextUtil.getBean(WarningReportMapper.class);
    private AppMapper appMapper = SpringContextUtil.getBean(AppMapper.class);
    private WarningInformLogMapper warningInformLogMapper = SpringContextUtil.getBean(WarningInformLogMapper.class);
    private CommonProperties commonProperties = SpringContextUtil.getBean(CommonProperties.class);
    private SendCloudComponent sendCloudComponent = SpringContextUtil.getBean(SendCloudComponent.class);

    private WarningConfigDTO warningConfig;

    public WarningThread(WarningConfigDTO warningConfig) {
        this.warningConfig = warningConfig;
    }


    @Override
    public void run() {
        Example example = new Example(WarningDataInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("ds", DateUtil.today()).andEqualTo("hour", DateUtil.thisHour(true)).andEqualTo("configId", warningConfig.getId());
        example.and(criteria);
        WarningDataInfo warningDataInfo1 = warningDataInfoMapper.selectOneByExample(example);
        if(warningDataInfo1!=null){
            return;
        }
        WarningDataInfo warningDataInfo = new WarningDataInfo();
        Map<String, String> data = new HashMap<>();
        Example exampleApp = new Example(App.class);
        exampleApp.and().andEqualTo("appkey",warningConfig.getAppkey());
        App app = appMapper.selectOneByExample(exampleApp);
        if(app==null){
            log.error("App为NULL：{}",warningConfig.toString());
            return;
        }
        data.put("os",app.getOs().equals("Android")?"2":"1");
        data.put("eval",warningConfig.getEval());
        data.put("appkey",warningConfig.getAppkey());
        data.put("cid",warningConfig.getCid());
        if(DateUtil.thisHour(true)==0){//零点日期时间差处理
            final String yesterday = DateUtil.yesterday().toString("yyyy-MM-dd");
            data.put("ds",yesterday);
            warningDataInfo.setDs(yesterday);
        }else{
            String today = DateUtil.today();
            data.put("ds",today);
            warningDataInfo.setDs(today);
        }

        String dataCycleRule = warningConfig.getDataCycleRule();
        if(dataCycleRule.equals("day")){
            data.put("startHour","0");
            String hour = String.valueOf(DateUtil.hour(DateUtil.offsetHour(new Date(), -1), true));
            data.put("endHour",hour);//前一小时
            //存时段时候endHour需要+1到当前时间段
            warningDataInfo.setTimeFrame("00:00~"+DateUtil.thisHour(true)+":00");
        }else{
            String hour = String.valueOf(DateUtil.hour(DateUtil.offsetHour(new Date(), -1), true));
            data.put("startHour",hour);//前一小时
            data.put("endHour",hour);//前一小时
            warningDataInfo.setTimeFrame(hour+":00~"+DateUtil.thisHour(true)+":00");
        }

        //查实时小时维度报表
        WarningDataInfo warning = null;
        try {
            warning = warningReportMapper.report(data);
        }catch (Exception e){
            log.error("预警监测任务异常:原始数据-{},Mapper参数-{}",warningConfig,data);
            return;
        }

        //判断
        if(warning.getWarningLimit()==1){
            warning.setCreateTime(DateUtil.now());
            warning.setTimeFrame(warningDataInfo.getTimeFrame());
            warning.setDs(warningDataInfo.getDs());
            warning.setConfigId(warningConfig.getId());
            warning.setHour(DateUtil.thisHour(true));
            Example exampleWarningAddressee = new Example(WarningAddressee.class);
            exampleWarningAddressee.and().andEqualTo("configId",warningConfig.getId()).andEqualTo("isusing",true);
            List<WarningAddressee> warningAddressees = warningAddresseeMapper.selectByExample(exampleWarningAddressee);
            List<WarningInformLog> warningInformLogs = new ArrayList<>();
            if(CollectionUtils.isEmpty(warningAddressees)) {
                warning.setInformed(0);//不通知只记录
            }else{//只要通知一个就记录为已通知（非第一次预警：所有用户都是一天只通知一次，期间新增了通知用户，所以要通知这个新增加的用户）
                List<String> addressees = new ArrayList<>();
                List<String> phones = new ArrayList<>();
                for (WarningAddressee warningAddressee : warningAddressees) {
                    //PushFrequency:推送频率：1当天仅推送一次2当天每小时均推送
                    if(warningAddressee.getPushFrequency()==2 || warningInformLogMapper.selectOneByCheckSended(warningAddressee,data.get("ds"))==null){
                        WarningInformLog warningInformLog = new WarningInformLog();
                        warningInformLog.setConfigId(warningConfig.getId());
                        warningInformLog.setCreateTime(DateUtil.now());
                        warningInformLog.setName(warningAddressee.getAddresseeName());
                        Integer pushType = warningAddressee.getPushType();
                        if(pushType==-1){
                            warningInformLog.setEmail(warningAddressee.getAddresseeEmail());
                            warningInformLog.setPhone(warningAddressee.getAddresseePhone());
                            addressees.add(warningAddressee.getAddresseeEmail());
                            phones.add(warningAddressee.getAddresseePhone());
                        }else if(pushType==1){
                            warningInformLog.setEmail(warningAddressee.getAddresseeEmail());
                            addressees.add(warningAddressee.getAddresseeEmail());
                        }else if(pushType==2){
                            phones.add(warningAddressee.getAddresseePhone());
                            warningInformLog.setPhone(warningAddressee.getAddresseePhone());
                        }
                        warningInformLogs.add(warningInformLog);
                        warning.setInformed(1);
                    }
                }
                //只通知需要通知的
                try {
                    if (!CollectionUtils.isEmpty(addressees)) {
                        //查询今日预警次数，时间往前推一小时查询，然后再加上本次
                        DateTime dateTime = DateUtil.offsetHour(new Date(), -1);
                        Example exampleCount = new Example(WarningDataInfo.class);
                        Example.Criteria criteriaCount = exampleCount.createCriteria();
                        criteriaCount.andEqualTo("ds", dateTime.toString(DatePattern.NORM_DATE_PATTERN)).andEqualTo("configId", warningConfig.getId());
                        exampleCount.and(criteriaCount);
                        int count = warningDataInfoMapper.selectCountByExample(exampleCount)+1;

                        String warningTitle = String.format(commonProperties.getWarningTitle(), warningConfig.getName());
                        //1-创建人姓名,2-预警名称,3-应用名称,4-渠道名称,5-计算区间,6-日期,7-触发预警时段,8-当日累计预警次数,9-创建人姓名(邮箱)
                        String warningContent = String.format(commonProperties.getWarningContent(), warningConfig.getActualName(), warningConfig.getName(), warningConfig.getName(), warningConfig.getAppName(), warningConfig.getChannelAlias(), warningConfig.getDataCycleRule().equals("day") ? "按天计算" : "按时计算", DateUtil.today(), warningDataInfo.getTimeFrame(), count, warningConfig.getActualName() + "(" + warningConfig.getCreateEmail() + ")");
                        //查询今日已经预警次数，是否包含本次
                        boolean sended = sendCloudComponent.sendMailReuse(addressees, warningTitle, warningContent, null, null);
                        if(sended){
                            warning.setInformed(1);
                        }else{
                            warning.setInformed(0);
                        }
                    }
                }catch (Exception e){
                    warning.setInformed(0);
                    log.error("预警检测-邮件发送失败：{},{}",warningConfig,e);
                }
                try {
                    if (!CollectionUtils.isEmpty(phones)) {
                        JSONObject vars = JSONUtil.createObj().set("username", warningConfig.getActualName()).set("name", warningConfig.getName());
                        boolean sended = sendCloudComponent.sendSMS(StrUtil.join(",",phones), sendCloudComponent.getWarningModel(), vars.toString());
                        if(sended){
                            warning.setInformed(1);
                        }else{
                            warning.setInformed(0);
                        }
                    }
                }catch (Exception e){
                    warning.setInformed(0);
                    log.error("预警检测-短信发送失败：{},{}",warningConfig,e);
                }
            }
            if(warning.getInformed()==null){
                warning.setInformed(0);
            }
            warningDataInfoMapper.insert(warning);
            if(!CollectionUtils.isEmpty(warningInformLogs)){
                for (WarningInformLog warningInformLog : warningInformLogs) {
                    warningInformLog.setDataInfoId(warning.getId());
                }
                warningInformLogMapper.insertList(warningInformLogs);
            }
        }
    }
}
