package com.fs.app.task;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fs.app.service.IpadSendServer;
import com.fs.common.core.redis.RedisCacheT;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.PubFun;
import com.fs.company.service.ICompanyMiniappService;
import com.fs.course.config.CourseConfig;
import com.fs.course.domain.FsCoursePlaySourceConfig;
import com.fs.course.service.IFsCoursePlaySourceConfigService;
import com.fs.ipad.vo.BaseVo;
import com.fs.qw.domain.QwIpadServer;
import com.fs.qw.domain.QwPushCount;
import com.fs.qw.domain.QwRestrictionPushRecord;
import com.fs.qw.domain.QwUser;
import com.fs.qw.mapper.QwIpadServerMapper;
import com.fs.qw.mapper.QwPushCountMapper;
import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
import com.fs.qw.mapper.QwUserMapper;
import com.fs.qw.service.impl.AsyncSopTestService;
import com.fs.qw.vo.QwSopCourseFinishTempSetting;
import com.fs.qw.vo.QwSopTempSetting;
import com.fs.sop.domain.QwSopLogs;
import com.fs.sop.mapper.QwSopLogsMapper;
import com.fs.sop.service.IQwSopLogsService;
import com.fs.system.domain.SysConfig;
import com.fs.system.mapper.SysConfigMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class SendMsg {

    private final QwUserMapper qwUserMapper;
    private final QwSopLogsMapper qwSopLogsMapper;
    private final IpadSendServer sendServer;
    private final SysConfigMapper sysConfigMapper;
    private final IQwSopLogsService qwSopLogsService;
    private final QwIpadServerMapper qwIpadServerMapper;
    private final RedisCacheT<Long> redisCache;
    private final AsyncSopTestService asyncSopTestService;
    private final ICompanyMiniappService companyMiniappService;
    private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
    private final QwPushCountMapper qwPushCountMapper;
    private final QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper;

    @Value("${group-no}")
    private String groupNo;
    private final List<QwUser> qwUserList = Collections.synchronizedList(new ArrayList<>());
    private final Map<Long, Long> qwMap = new ConcurrentHashMap<>();

    @Autowired
    @Qualifier("customThreadPool")
    private ThreadPoolTaskExecutor customThreadPool;

    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache, AsyncSopTestService asyncSopTestService, ICompanyMiniappService companyMiniappService, IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService, QwPushCountMapper qwPushCountMapper, QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper) {
        this.qwUserMapper = qwUserMapper;
        this.qwSopLogsMapper = qwSopLogsMapper;
        this.sendServer = sendServer;
        this.sysConfigMapper = sysConfigMapper;
        this.qwSopLogsService = qwSopLogsService;
        this.qwIpadServerMapper = qwIpadServerMapper;
        this.redisCache = redisCache;
        this.asyncSopTestService = asyncSopTestService;
        this.companyMiniappService = companyMiniappService;
        this.fsCoursePlaySourceConfigService = fsCoursePlaySourceConfigService;
        this.qwPushCountMapper = qwPushCountMapper;
        this.qwRestrictionPushRecordMapper = qwRestrictionPushRecordMapper;
    }
    private List<QwUser> getQwUserList() {
        if (qwUserList.isEmpty()) {
            List<QwIpadServer> serverList = qwIpadServerMapper.selectList(new QueryWrapper<QwIpadServer>().eq("group_no", groupNo));
            if (serverList.isEmpty()) {
                log.info("没找到可用的服务器 {} ",serverList);
                return new ArrayList<>();
            }
            List<Long> serverIds = PubFun.listToNewList(serverList, QwIpadServer::getId);
            List<QwUser> qwUsers = qwUserMapper.selectList(new QueryWrapper<QwUser>().eq("send_msg_type", 1).eq("server_status", 1).eq("ipad_status", 1).in("server_id", serverIds));
            qwUserList.addAll(qwUsers);
        }
        log.info("getQwUserList {}",JSON.toJSONString(qwUserList));
        return qwUserList;
    }

    private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
        List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().ne("type", 2).eq("is_del", 0));
//        log.info("获取到的小程序配置：{}", JSON.toJSONString(list));
//        log.info("获取到的小程序配置：{}", JSON.toJSONString(list));
        return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);
    }


    @Scheduled(fixedRate = 50000) // 每50秒执行一次
    public void refulsQwUserList() {
        qwUserList.clear();
    }
    @Scheduled(fixedDelay = 20000) // 每20秒执行一次
    public void sendMsg2() {
        log.info("执行日志：{}", LocalDateTime.now());
        if (StringUtils.isEmpty(groupNo)) {
            log.error("corpId为空不执行");
            return;
        }
        // 看课配置文件获取
        SysConfig courseConfig = sysConfigMapper.selectConfigByConfigKey("course.config");
        CourseConfig config = JSON.parseObject(courseConfig.getConfigValue(), CourseConfig.class);
        // 消息发送延迟
        int delayStart;
        int delayEnd;
        if (config.getDelayStart() == null || config.getDelayEnd() == null) {
            log.debug("消息发送延迟为空手动设置1000ms - 2000ms");
            delayStart = 1000;
            delayEnd = 2000;
        } else {
            delayStart = config.getDelayStart();
            delayEnd = config.getDelayEnd();
        }
        // 小程序配置获取
        Map<String, FsCoursePlaySourceConfig> miniMap = getMiniMap();
        // 获取 pad 发送的企微
        getQwUserList().forEach(e -> {
            // 如果没有值就执行后面的方法 并且入值
            qwMap.computeIfAbsent(e.getId(), k -> {
                // 线程启动
                CompletableFuture.runAsync(() -> {
                    try {
                        log.info("开始任务：{}", e.getQwUserName());
                        // 开始任务
                        processUser(e, delayStart, delayEnd, miniMap);
                    } catch (Exception exception) {
                        log.error("发送错误：", exception);
                    } finally {
                        log.info("删除任务：{}", e.getQwUserName());
                        qwMap.remove(e.getId());
//                        removeQwMap.putIfAbsent(e.getId(), System.currentTimeMillis());
                    }
                }, customThreadPool);
                return System.currentTimeMillis(); // 占位值
            });
        });
    }

    /**
     * 发送任务执行
     * @param qwUser     发送企微
     * @param delayStart 随机延迟 最小值
     * @param delayEnd   随机延迟 最大值
     * @param miniMap    小程序配置
     */
    private void processUser(QwUser qwUser, int delayStart, int delayEnd, Map<String, FsCoursePlaySourceConfig> miniMap) {
        long start1 = System.currentTimeMillis();
        // 获取当前企微待发送记录
        List<QwSopLogs> qwSopLogList = qwSopLogsMapper.selectByQwUserId(qwUser.getId());
        if (qwSopLogList.isEmpty()) {
            log.info("获取当前企微待发送记录为空");
            return;
        }
        // 获取企微用户
        QwUser user = qwUserMapper.selectById(qwUser.getId());
        BaseVo parentVo = new BaseVo();
        parentVo.setCorpCode(qwUser.getCorpId());
        long end1 = System.currentTimeMillis();
        // 判断这个企微是否需要发送
        if (!sendServer.isSend(user, parentVo)) {
            log.info("当前这个企微不需要发送 数据{}",user);
            return;
        }
        log.info("销售：{}, 消息：{}, 耗时: {}, 时间：{}", user.getQwUserName(), qwSopLogList.size(), end1 - start1, qwMap.get(qwUser.getId()));
        long start3 = System.currentTimeMillis();
        // 循环代发送消息
        for (QwSopLogs qwSopLogs : qwSopLogList) {
            long start2 = System.currentTimeMillis();
            QwSopCourseFinishTempSetting setting = JSON.parseObject(qwSopLogs.getContentJson(), QwSopCourseFinishTempSetting.class);
            // 判断消息状态是否满足发送条件
            if (!sendServer.isSendLogs(qwSopLogs, setting, user)) {
                log.info("销售：{}, 消息发送条件未满足：{}", user.getQwUserName(), qwSopLogs.getId());
                continue;
            }
            log.info("进入发送消息状态：{}", qwSopLogs.getId());
            String key = "qw:logs:pad:send:id:" + qwSopLogs.getId();
            Long time = redisCache.getCacheObject(key);
            // 判断这个消息有没有进入过发送，如果进了就不要再发了，防止重复发送，，，，， TODO 千万不能动！！！！！
            if (redisCache.getCacheObject(key) != null) {
                log.error("{}已有发送：{}, :{}", qwUser.getQwUserName(), qwSopLogs.getId(), time);
                continue;
            }
            redisCache.setCacheObject(key, System.currentTimeMillis(), 24, TimeUnit.HOURS);
            List<QwPushCount> pushCountList = qwPushCountMapper.selectQwPushCountLists();
            Map<Integer, List<QwPushCount>> pushMap = pushCountList.stream().collect(Collectors.groupingBy(QwPushCount::getType));
            // 循环发送消息里面的每一条消息
            for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
                long start4 = System.currentTimeMillis();
                //判断当前销售推送客户消息限制
                Long qwUserId = qwUser.getId();//销售的Id
                Integer type = Integer.valueOf(content.getContentType());//发送消息的类型
                Long customerId = qwSopLogs.getExternalId();//客户ID
                Long companyId = qwSopLogs.getCompanyId();//公司ID
                Integer pushCount = -99;
                if(pushMap.containsKey(type)){
                    List<QwPushCount> qwPushCounts = pushMap.get(type);
                    Optional<QwPushCount> optional = qwPushCounts.stream().filter(e -> Objects.equals(e.getCompanyId(), companyId)).findFirst();
                    if(optional.isPresent()){
                        pushCount = optional.get().getPushCount();
                    }else{
                        Optional<QwPushCount> nullCount = qwPushCounts.stream().filter(e -> e.getCompanyId() == null).findFirst();
                        if(nullCount.isPresent()){
                            pushCount = nullCount.get().getPushCount();
                        }
                    }
                }
                //查询是否有设置限制客服推送消息次数
//                    Integer pushCount=pushCountMap.containsKey(String.valueOf(companyId)) ? pushCountMap.get(String.valueOf(companyId)): pushCountMap.getOrDefault(String.valueOf(type), -99);
                int salesPushCustomerMessageCount = qwRestrictionPushRecordMapper.selectQwRestrictionPushRecord(qwUserId, customerId, type, DateUtils.toStartTime(), DateUtils.toEndTime());
                if (pushCount != -99 && salesPushCustomerMessageCount >= pushCount) {
                    content.setSendStatus(2);//设置发送失败状态
                    content.setSendRemarks("发送次数达到上限");
                } else {
                    // 发送
                    sendServer.send(content, user, qwSopLogs, miniMap, parentVo);
                    //判断销售推送成功：保存记录
                    if (content.getSendStatus() != 2) {
                        QwRestrictionPushRecord qrpr = new QwRestrictionPushRecord();
                        qrpr.setType(type);
                        qrpr.setQwUserId(qwUserId);
                        qrpr.setQwExternalId(customerId);
                        qrpr.setCompanyId(companyId);
                        qrpr.setStatus(1);
                        qrpr.setCreateTime(DateUtils.getTime());
                        qrpr.setTime(System.currentTimeMillis());
                        qwRestrictionPushRecordMapper.insert(qrpr);
                    }
                    long end4 = System.currentTimeMillis();
                    log.info("请求pad发送完成：{}, {}, 时长4：{}", user.getQwUserName(), qwSopLogs.getId(), end4 - start4);
                    if(content.getSendStatus() == 2 && ("请求失败：消息发送过于频繁，请稍后再试".equals(content.getSendRemarks()) || "请求失败：请求频率异常".equals(content.getSendRemarks()))){
                        QwUser update = new QwUser();
                        update.setRemark("请求频率异常，暂停发送，三小时后恢复继续发送");
                        update.setUpdateTime(new Date());
                        qwUserMapper.update(update, new QueryWrapper<QwUser>().eq("id", user.getId()));
                        redisCache.setCacheObject("qw:user:id:" + user.getId(), user.getId(), 3, TimeUnit.HOURS);
                        return;
                    }
                    try {
                        int delay = ThreadLocalRandom.current().nextInt(300, 1000);
                        log.debug("pad发送消息等待：{}ms", delay);
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        log.error("线程等待错误！");
                    }
                }
            }
            // 推送 APP
            if (!setting.getSetting().isEmpty()) {
                new Thread(() -> {
                    try {
                        List<QwSopTempSetting.Content.Setting> settings = JSON.parseArray(JSON.toJSONString(setting.getSetting()), QwSopTempSetting.Content.Setting.class).stream().filter(e -> "9".equals(e.getContentType())).collect(Collectors.toList());
                        asyncSopTestService.asyncSendMsgBySopAppLinkNormalIM(settings, qwSopLogs.getCorpId(), user.getCompanyUserId(), qwSopLogs.getFsUserId());
                    } catch (Exception e) {
                        log.error("推送APP失败", e);
                    }
                }).start();
            }
            qwSopLogs.setSend(true);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            QwSopLogs updateQwSop = new QwSopLogs();
            updateQwSop.setId(qwSopLogs.getId());
            // 是否全部发送失败
            if (setting.getSetting().stream().allMatch(e -> e.getSendStatus() == 2)) {
                updateQwSop.setReceivingStatus(0L);
                updateQwSop.setSendStatus(0L);
                updateQwSop.setRemark("全部发送失败");
            } else if (setting.getSetting().stream().anyMatch(e -> e.getSendStatus() == 2)) {
                updateQwSop.setReceivingStatus(1L);
                updateQwSop.setSendStatus(1L);
                updateQwSop.setRemark("部分发送失败");
                updateQwSop.setRealSendTime(sdf.format(new Date()));
            } else {
                updateQwSop.setReceivingStatus(1L);
                updateQwSop.setSendStatus(1L);
                updateQwSop.setRemark("全部发送成功");
                updateQwSop.setRealSendTime(sdf.format(new Date()));
            }
            updateQwSop.setContentJson(JSON.toJSONString(setting));
            long end2 = System.currentTimeMillis();
            int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
            log.info("销售：{}, 修改条数{}, 发送方消息完成：{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(), end2 - start2);
            try {
                int delay = ThreadLocalRandom.current().nextInt(delayStart, delayEnd);
                log.debug("企微发送消息等待：{}ms", delay);
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                log.error("线程等待错误！");
            }
        }
        long end3 = System.currentTimeMillis();
        log.info("销售执行完成：{}, 耗时：{}", user.getQwUserName(), end3 - start3);
    }
}
