package com.pcloud.book.timecontrol.biz.impl;

import static com.pcloud.book.guide.constant.PcloudGuideRedisConstant.PCLOUD_WAKE_UP_CRON_JOB;

import com.alibaba.fastjson.JSON;
import com.pcloud.appcenter.app.dto.AppDto;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.constant.BookConstant;
import com.pcloud.book.consumer.app.AppConsr;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.content.ResourceConsr;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.WeixinQrcodeBiz;
import com.pcloud.book.group.enums.AppAndProductTypeEnum;
import com.pcloud.book.group.tools.SendWeixinRequestTools;
import com.pcloud.book.keywords.enums.ReplyTypeEnum;
import com.pcloud.book.skill.dao.PcloudSkillDao;
import com.pcloud.book.skill.entity.PcloudSkill;
import com.pcloud.book.skill.enums.SkillTypeEnum;
import com.pcloud.book.timecontrol.biz.TaskBiz;
import com.pcloud.book.timecontrol.biz.TaskSubscribeBiz;
import com.pcloud.book.timecontrol.dto.BookTaskBindingDto;
import com.pcloud.book.timecontrol.dto.CreateReplyMessageDto;
import com.pcloud.book.timecontrol.dto.CreateTaskDto;
import com.pcloud.book.timecontrol.dto.CreateTaskItemDto;
import com.pcloud.book.timecontrol.dto.LabelDto;
import com.pcloud.book.timecontrol.dto.ReplyMessageBaseDto;
import com.pcloud.book.timecontrol.dto.ReplyMessageDto;
import com.pcloud.book.timecontrol.dto.TaskDto;
import com.pcloud.book.timecontrol.dto.TaskItemDto;
import com.pcloud.book.timecontrol.dto.UpdateTaskDto;
import com.pcloud.book.timecontrol.dto.UpdateTaskItemDto;
import com.pcloud.book.timecontrol.entity.*;
import com.pcloud.book.timecontrol.enums.SendTypeEnum;
import com.pcloud.book.timecontrol.enums.TaskPrizeTypeEnum;
import com.pcloud.book.timecontrol.enums.TaskSendStateEnum;
import com.pcloud.book.timecontrol.enums.TimeControlPushTypeEnum;
import com.pcloud.book.timecontrol.mapper.*;
import com.pcloud.book.timecontrol.vo.KeyWordTaskVO;
import com.pcloud.book.util.common.YesOrNoEnums;
import com.pcloud.channelcenter.wechat.dto.AccountSettingDto;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.dto.ResponseDto;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.ResponseHandleUtil;
import com.pcloud.common.utils.ServeLinkUtils;
import com.pcloud.common.utils.httpclient.UrlUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.common.utils.string.StringUtilParent;
import com.pcloud.contentcenter.resource.dto.ResourceDTO;
import com.pcloud.facade.quartz.entity.CallBackParam;
import com.pcloud.facade.quartz.entity.ScheduleJob;
import com.pcloud.facade.quartz.service.ScheduleService;
import com.pcloud.labelcenter.label.service.LabelService;
import com.pcloud.wechatgroup.base.exception.WechatGroupBizException;
import com.pcloud.wechatgroup.group.dto.GroupRobotDTO;
import com.sdk.wxgroup.RobotProcessTypeEnum;
import com.sdk.wxgroup.SendArticleMessageVO;
import com.sdk.wxgroup.SendFileVO;
import com.sdk.wxgroup.SendMessageTypeEnum;
import com.sdk.wxgroup.SendPicMessageVO;
import com.sdk.wxgroup.SendTextMessageVO;
import io.swagger.models.auth.In;
import java.sql.Struct;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.jackson.JsonParseException;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

/**
 * @date: 2020年01月30日 14:20
 * @Author: Zcy
 * @Descprition
 */
@Slf4j
@Component("taskBiz")
public class TaskBizImpl implements TaskBiz {

    private final static Logger LOGGER = LoggerFactory.getLogger(TaskBizImpl.class);

    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(4);

    @Autowired
    private PcloudSkillDao pcloudSkillDao;
    @Autowired
    private TimeControlTaskMapper taskMapper;
    @Autowired
    private TimeControlTaskItemMapper taskItemMapper;
    @Autowired
    private TimeControlTaskItemWeekMapper taskItemWeekMapper;
    @Autowired
    private TimeControlReplyMessageMapper replyMessageMapper;
    @Autowired
    private BookTaskBindingMapper bookTaskBindingMapper;
    @Autowired
    private TimeControlTaskSubscribeMapper taskSubscribeMapper;
    @Autowired
    private TimeControlTaskSendMapper timeControlTaskSendMapper;
    @Autowired
    private LabelService labelService;
    @Autowired
    private TaskSubscribeBiz taskSubscribeBiz;
    //@Autowired
    //private PcloudKeywordService pcloudKeywordService;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private WeixinQrcodeBiz weixinQrcodeBiz;
    @Autowired
    private TaskPrizeMapper taskPrizeMapper;
    @Autowired
    private TaskPrizeItemMapper taskPrizeItemMapper;
    @Autowired
    private AppConsr appConsr;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private TaskPrizeBizImpl taskPrizeBiz;
    @Autowired
    private ResourceConsr resourceConsr;
    @Autowired
    private ProductConsr productConsr;
    @Autowired
    private ScheduleService scheduleService;
    @Autowired
    private TimeControlTaskItemWeekMapper timeControlTaskItemWeekMapper;

    @Override
    public Integer createTask(CreateTaskDto createTaskDto) {
        TimeControlTask timeControlTask = new TimeControlTask();
        BeanUtils.copyProperties(createTaskDto, timeControlTask);
        taskMapper.insert(timeControlTask);
        return timeControlTask.getTaskId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTask(Integer taskId) {
        PcloudSkill byRelId = pcloudSkillDao.getByRelId(taskId, SkillTypeEnum.TIME_MANAGE.value);
        if (Objects.nonNull(byRelId)) {
            throw new BookBizException(BookBizException.PARAM_IS_EXIST, "该计划已经关联技能，无法删除！");
        }
        TimeControlTask timeControlTask = taskMapper.selectByPrimaryKey(taskId);
        // 1删除任务模板
        taskMapper.deleteByPrimaryKey(taskId);
        // 2删除书与任务之间的关联关系
        bookTaskBindingMapper.deleteByTask(taskId);
        // 3删除用户对这个任务的订阅关系
        taskSubscribeMapper.unSubscribeTaskByTaskId(taskId);
        //4 取消待发送的任务
        timeControlTaskSendMapper.cancelSendByTaskId(taskId);
        //取消定时任务
        if (SendTypeEnum.SEND_WEEK.state.equals(timeControlTask.getSendType())){
            deleteQuartz4TaskId(taskId);
        }
        taskItemMapper.deleteByTaskId(taskId);
    }

    @Override
    public void updateTask(UpdateTaskDto updateTaskDto) {
        TimeControlTask timeControlTask = new TimeControlTask();
        BeanUtils.copyProperties(updateTaskDto, timeControlTask);
        taskMapper.updateTask(timeControlTask);
        //同步任务名称
        bookTaskBindingMapper.updateTaskName(updateTaskDto.getTaskId(), updateTaskDto.getTaskName());
    }

    @Override
    public TaskDto getTaskById(Integer taskId) {
        TimeControlTask timeControlTask = taskMapper.selectByPrimaryKey(taskId);
        if (null != timeControlTask) {
            TaskDto taskDto = new TaskDto();
            BeanUtils.copyProperties(timeControlTask, taskDto);
            return taskDto;
        }
        return null;
    }

    @Override
    public PageBeanNew<TaskDto> listTask4Pcloud(Integer currentPage, Integer numPerPage, String search) {
        List<TaskDto> list = new ArrayList<>();
        Integer count = taskMapper.getTaskCount(search);
        if (count <= 0) {
            return new PageBeanNew<>(currentPage, numPerPage, list);
        }
        list = taskMapper.listTask4Pcloud(currentPage * numPerPage, numPerPage, search);

        // 封装标签 统计数据
        Set<Long> labelSet = new HashSet<>();
        // 获取所有标签 统一获取标签名称
        list.forEach(item -> {
            labelSet.add(item.getProLabelId());
            labelSet.add(item.getDepLabelId());
            labelSet.add(item.getPurLabelId());
        });

        labelSet.remove(null);
        if (labelSet.size() > 0) {
            try {
                // 批量获取标签名称
                ResponseEntity<ResponseDto<Map<Long, String>>> response = labelService.getLabelName(new ArrayList<>(labelSet));
                Map<Long, String> labelMap = ResponseHandleUtil.parseMap(response, Long.class, String.class);
                // 补充标签名称
                list.forEach(item -> {
                    item.setProLabelName(labelMap.get(item.getProLabelId()));
                    item.setDepLabelName(labelMap.get(item.getDepLabelId()));
                    item.setPurLabelName(labelMap.get(item.getPurLabelId()));
                    String filterStr = StringUtilParent.replaceHtml(item.getTaskIntroduce());
                    String subStr = filterStr.length() > 60 ? filterStr.substring(0, 60) + "..." : filterStr;
                    item.setCutTaskIntroduce(subStr);
                });
            } catch (Exception e) {
                log.error("labelService.getLabelName 批量获取标签名称失败" + e.getMessage());
            }
        }
        return new PageBeanNew<>(currentPage, numPerPage, count, list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer  createTaskItem(CreateTaskItemDto createTaskItemDto) {
        Integer taskId = createTaskItemDto.getTaskId();
        Integer startDay = createTaskItemDto.getStartDay();
        TimeControlTask timeControlTask = taskMapper.selectByPrimaryKey(taskId);
        if (null == timeControlTask) {
            return null;
        }
        List<CreateReplyMessageDto> replyMessageList = createTaskItemDto.getReplyMessageList();
        if (ListUtils.isEmpty(replyMessageList)) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "请至少填写一条任务提醒");
        }
        if (replyMessageList.size() > 3) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "至多填写3条任务提醒");
        }
        //检验是否存在当天定时任务
        /*TimeControlTaskItem item = taskItemMapper.getByTaskIdAndDay(taskId, startDay);
        if (null != item) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "已配置过当天消息!");
        }*/
        List<CreateReplyMessageDto> completedReplyMessageList = createTaskItemDto.getCompletedReplyMessageList();
        if(null!=createTaskItemDto.getFinishConfirm() && createTaskItemDto.getFinishConfirm()==1){
            if (StringUtil.isEmpty(createTaskItemDto.getFinishLinkIntroduce())) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "任务完成资源封装链接介绍不能为空！");
            }
            if (StringUtil.isEmpty(createTaskItemDto.getFinishLinkUrl())) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "任务完成资源封装链接地址不能为空！");
            }
            if (ListUtils.isEmpty(completedReplyMessageList)) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "请至少填写一条完成任务提醒");
            }
            if (completedReplyMessageList.size() > 4) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "至多填写3条完成任务提醒");
            }
        }
        TimeControlTaskItem item = new TimeControlTaskItem();
        BeanUtils.copyProperties(createTaskItemDto, item);
        if (null == item.getFinishConfirm()) {
            item.setFinishConfirm(0);
        }
        if(null==item.getTdConfirm()){
            item.setTdConfirm(0);
        }
        if(null==item.getAddSendTime()){
            item.setAddSendTime(0);
        }
        if(null == item.getProgressGuidance()) {
            item.setProgressGuidance(0);
        }
        taskItemMapper.insert(item);
        Integer taskItemId = item.getId();
        List<TimeControlWeekDay> weekDayList=new ArrayList<>();
        if (!ListUtils.isEmpty(createTaskItemDto.getWeekdays())){
            for (Integer weekDay:createTaskItemDto.getWeekdays()) {
                TimeControlWeekDay timeControlWeekDay=new TimeControlWeekDay();
                timeControlWeekDay.setTaskItemId(taskItemId);
                timeControlWeekDay.setWeekDay(weekDay);
                weekDayList.add(timeControlWeekDay);
            }
            taskItemWeekMapper.batchInsert(weekDayList);
        }
        List<TimeControlReplyMessage> list = new ArrayList<>();
        replyMessageList.forEach(message -> {
            TimeControlReplyMessage replyMessage = new TimeControlReplyMessage();
            BeanUtils.copyProperties(message, replyMessage);
            replyMessage.setTaskItemId(taskItemId);
            replyMessage.setTaskId(taskId);
            replyMessage.setType(0);
            list.add(replyMessage);
        });
        //任务完成回复消息list
        if(null!=createTaskItemDto.getFinishConfirm() && createTaskItemDto.getFinishConfirm()==1){
            List<TimeControlReplyMessage> messageList = new ArrayList<>();
            completedReplyMessageList.forEach(message -> {
                TimeControlReplyMessage replyMessage = new TimeControlReplyMessage();
                BeanUtils.copyProperties(message, replyMessage);
                replyMessage.setTaskItemId(taskItemId);
                replyMessage.setTaskId(taskId);
                replyMessage.setType(1);
                list.add(replyMessage);
            });
        }
        replyMessageMapper.batchInsert(list);
        if (SendTypeEnum.SEND_WEEK.state.equals(timeControlTask.getSendType())){
            EXECUTOR_SERVICE.execute(()->{
                addTask4AddTimeControl(createTaskItemDto,taskItemId);
            });
        }
        return taskItemId;
    }

    private void addTask4AddTimeControl(CreateTaskItemDto createTaskItemDto, Integer taskItemId) {
        log.info("新增计划时新增定时任务createTaskItemDto：{}，taskItemId：{}",createTaskItemDto,taskItemId);
        try {
            int hour = Integer.parseInt(createTaskItemDto.getSendHour().substring(0, 2));
            String weeks = "";
            if (TimeControlPushTypeEnum.SEND_EVERY_DAY.state.equals(createTaskItemDto.getPushType())){
                weeks = "1,2,3,4,5,6,7";
            }else if (TimeControlPushTypeEnum.SEND_4_WEEK.state.equals(createTaskItemDto.getPushType())){
                List<Integer> weekdays = createTaskItemDto.getWeekdays();
                for (Integer weekDay : weekdays) {
                    if (weekDay == 7) {
                        weekDay = 1;
                    } else {
                        weekDay = weekDay + 1;
                    }
                    weeks = weeks + weekDay + ",";
                }
                weeks= weeks.substring(0,weeks.length()-1);
            }
            String cronStr = 0 + " " + 0 + " " + hour + " ? * " + weeks;
            String jobName = BookConstant.TIME_CONTROL_SEND + taskItemId;
            ScheduleJob job = new ScheduleJob();
            //定时器任务
            job.setJobName(jobName);
            //cron表达式
            job.setCronExpression(cronStr);
            //定时器分组
            job.setJobGroup("book");
            CallBackParam param = new CallBackParam();
            //service名称
            param.setBeanName("timeControlTaskService");
            //回调内部接口方法名称
            param.setMethodName("sendTimeTaskMessage4Week");
            //设置回调参数
            Map<String, Object> map = new HashMap<>();
            map.put("jobName", jobName);
            map.put("taskItemId",taskItemId);
            param.setParamMap(map);
            Map<String, Object> scheduleMap = new HashMap<>();
            scheduleMap.put("scheduleJob", job);
            scheduleMap.put("callBackParam", param);
            scheduleService.addCronJob(scheduleMap);
        } catch (SchedulerException | JsonParseException e) {
            log.info("【TaskBizImpl.createCronJob】创建定时任务失败", e);
        }

    }

    @Override
    @Transactional
    public void deleteTaskItem(Integer taskItemId) {
        taskItemMapper.deleteByPrimaryKey(taskItemId);
        replyMessageMapper.deleteByItemId(taskItemId);
        //删除待发送任务
        timeControlTaskSendMapper.cancelSendByItemId(taskItemId);
        timeControlTaskItemWeekMapper.batchDelete(Stream.of(taskItemId).collect(Collectors.toList()));
        //删除定时任务
        try {
            scheduleService.deleteJob( BookConstant.TIME_CONTROL_SEND + taskItemId, "book");
        } catch (Exception e) {
            log.error("删除定时任务失败,taskItemId+" + taskItemId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTaskItem(UpdateTaskItemDto updateTaskItemDto) {
        Integer taskItemId = updateTaskItemDto.getId();
        TimeControlTaskItem timeControlTaskItem = taskItemMapper.selectByPrimaryKey(taskItemId);
        if (null == timeControlTaskItem) {
            return;
        }
        Integer taskId = timeControlTaskItem.getTaskId();
        Integer startDay = updateTaskItemDto.getStartDay();
        TimeControlTask timeControlTask = taskMapper.selectByPrimaryKey(taskId);
        if (null == timeControlTask) {
            return;
        }
        List<CreateReplyMessageDto> replyMessageList = updateTaskItemDto.getReplyMessageList();
        if (ListUtils.isEmpty(replyMessageList)) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "请至少填写一条任务提醒");
        }
        if (replyMessageList.size() > 3) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "至多填写3条任务提醒");
        }
        //检验是否存在当天定时任务
        /*TimeControlTaskItem item = taskItemMapper.getByTaskIdAndDay(taskId, startDay);
        if (null != item && !item.getId().equals(taskItemId)) {
            throw new WechatGroupBizException(WechatGroupBizException.ERROR, "已配置过当天消息!");
        }*/
        List<CreateReplyMessageDto> completedReplyMessageList = updateTaskItemDto.getCompletedReplyMessageList();
        if(null!=updateTaskItemDto.getFinishConfirm() && updateTaskItemDto.getFinishConfirm()==1){
            if (StringUtil.isEmpty(updateTaskItemDto.getFinishLinkIntroduce())) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "任务完成资源封装链接介绍不能为空！");
            }
            if (StringUtil.isEmpty(updateTaskItemDto.getFinishLinkUrl())) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "任务完成资源封装链接地址不能为空！");
            }
            if (ListUtils.isEmpty(completedReplyMessageList)) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "请至少填写一条完成任务提醒");
            }
            if (completedReplyMessageList.size() > 4) {
                throw new WechatGroupBizException(WechatGroupBizException.ERROR, "至多填写3条完成任务提醒");
            }
        }
        BeanUtils.copyProperties(updateTaskItemDto, timeControlTaskItem);
        if (null == timeControlTaskItem.getFinishConfirm()) {
            timeControlTaskItem.setFinishConfirm(0);
        }
        if(null == timeControlTaskItem.getTdConfirm()){
            timeControlTaskItem.setTdConfirm(0);
        }
        if(null == timeControlTaskItem.getAddSendTime()){
            timeControlTaskItem.setAddSendTime(0);
        }
        if (null == timeControlTaskItem.getProgressGuidance()) {
            timeControlTaskItem.setProgressGuidance(0);
        }
        taskItemMapper.updateTaskItem(timeControlTaskItem);
        //删除原week配置
        timeControlTaskItemWeekMapper.batchDelete(Stream.of(timeControlTaskItem.getId()).collect(Collectors.toList()));
        List<TimeControlWeekDay> weekDayList=new ArrayList<>();
        if (!ListUtils.isEmpty(updateTaskItemDto.getWeekdays())){
            for (Integer weekDay: updateTaskItemDto.getWeekdays()) {
                TimeControlWeekDay timeControlWeekDay=new TimeControlWeekDay();
                timeControlWeekDay.setTaskItemId(taskItemId);
                timeControlWeekDay.setWeekDay(weekDay);
                weekDayList.add(timeControlWeekDay);
            }
            taskItemWeekMapper.batchInsert(weekDayList);
        }
        //删除原item下的配置
        replyMessageMapper.deleteByItemId(taskItemId);
        //重新插入
        List<TimeControlReplyMessage> list = new ArrayList<>();
        replyMessageList.forEach(message -> {
            TimeControlReplyMessage replyMessage = new TimeControlReplyMessage();
            BeanUtils.copyProperties(message, replyMessage);
            replyMessage.setTaskItemId(taskItemId);
            replyMessage.setTaskId(taskId);
            replyMessage.setType(0);
            list.add(replyMessage);
        });
        //任务完成回复消息list
        if(null!=updateTaskItemDto.getFinishConfirm() && updateTaskItemDto.getFinishConfirm()==1){
            List<TimeControlReplyMessage> messageList = new ArrayList<>();
            completedReplyMessageList.forEach(message -> {
                TimeControlReplyMessage replyMessage = new TimeControlReplyMessage();
                BeanUtils.copyProperties(message, replyMessage);
                replyMessage.setTaskItemId(taskItemId);
                replyMessage.setTaskId(taskId);
                replyMessage.setType(1);
                list.add(replyMessage);
            });
        }
        replyMessageMapper.batchInsert(list);
    }

    @Override
    public TaskItemDto getTaskItem(Integer id) {
        TaskItemDto taskItemDto = new TaskItemDto();
        TimeControlTaskItem timeControlTaskItem = taskItemMapper.selectByPrimaryKey(id);
        if(timeControlTaskItem==null){
            return new TaskItemDto();
        }
        BeanUtils.copyProperties(timeControlTaskItem, taskItemDto);
        List<TimeControlWeekDay> weekDayList=taskItemWeekMapper.selectByItemId(id);
        List<Integer> weekdays=new ArrayList<>();
        for (TimeControlWeekDay weekDay:weekDayList) {
            weekdays.add(weekDay.getWeekDay());
        }
        taskItemDto.setWeekdays(weekdays);
        if (null == timeControlTaskItem) {
            return taskItemDto;
        }
        List<TimeControlReplyMessage> list = replyMessageMapper.list4TaskItem(id, 0);
        List<TimeControlReplyMessage> completeReplyMessageList = replyMessageMapper.list4TaskItem(id, 1);
        List<ReplyMessageDto> messageDtos = new ArrayList<>();
        if (!ListUtils.isEmpty(list)) {
            list.forEach(message -> {
                ReplyMessageDto replyMessageDto = new ReplyMessageDto();
                BeanUtils.copyProperties(message, replyMessageDto);
                messageDtos.add(replyMessageDto);
                if (ReplyTypeEnum.RESOURCE.value.equals(message.getReplyType())) {
                    Long resourceId = message.getResourceId();
                    Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(resourceId));
                    ResourceDTO resourceDTO = map.get(resourceId);
                    if (resourceDTO != null) {
                        replyMessageDto.setResourceName(resourceDTO.getResourceName());
                        replyMessageDto.setResourceUrl(resourceDTO.getFileUrl());
                        replyMessageDto.setFileType(resourceDTO.getFileType());
                        replyMessageDto.setFileSize(resourceDTO.getFileSize());
                        replyMessageDto.setResourceTypeCode(resourceDTO.getTypeCode());
                    }
                }
            });
        }
        taskItemDto.setReplyMessageList(messageDtos);
        //完成任务回复消息List
        List<ReplyMessageDto> completedMessageDtos = new ArrayList<>();
        if(!ListUtils.isEmpty(completeReplyMessageList)){
            completeReplyMessageList.forEach(message -> {
                ReplyMessageDto replyMessageDto = new ReplyMessageDto();
                BeanUtils.copyProperties(message, replyMessageDto);
                completedMessageDtos.add(replyMessageDto);
                if (ReplyTypeEnum.RESOURCE.value.equals(message.getReplyType())) {
                    Long resourceId = message.getResourceId();
                    Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(resourceId));
                    ResourceDTO resourceDTO = map.get(resourceId);
                    if (resourceDTO != null) {
                        replyMessageDto.setResourceName(resourceDTO.getResourceName());
                        replyMessageDto.setResourceUrl(resourceDTO.getFileUrl());
                        replyMessageDto.setFileType(resourceDTO.getFileType());
                        replyMessageDto.setFileSize(resourceDTO.getFileSize());
                        replyMessageDto.setResourceTypeCode(resourceDTO.getTypeCode());
                    }
                }
            });
        }
        taskItemDto.setCompletedReplyMessageList(completedMessageDtos);
        return taskItemDto;
    }

    @Override
    public List<ReplyMessageBaseDto> listTaskItemDay(Integer taskId) {
        return taskItemMapper.listTaskItemDay(taskId);
    }

    @Override
    public List<BookTaskBindingDto> listTask(String search) {
        List<BookTaskBindingDto> list = taskMapper.listTask(search);
        if (!ListUtils.isEmpty(list)) {
            // 封装标签 统计数据
            Set<Long> labelSet = new HashSet<>();
            // 获取所有标签 统一获取标签名称
            list.forEach(item -> {
                labelSet.add(item.getProLabelId());
                labelSet.add(item.getDepLabelId());
                labelSet.add(item.getPurLabelId());
            });

            labelSet.remove(null);
            if (labelSet.size() > 0) {
                // 批量获取标签名称
                ResponseEntity<ResponseDto<Map<Long, String>>> response = labelService.getLabelName(new ArrayList<>(labelSet));
                Map<Long, String> labelMap = ResponseHandleUtil.parseMap(response, Long.class, String.class);
                // 补充标签名称
                list.forEach(item -> {
                    item.setProLabelName(labelMap.get(item.getProLabelId()));
                    item.setDepLabelName(labelMap.get(item.getDepLabelId()));
                    item.setPurLabelName(labelMap.get(item.getPurLabelId()));
                });
            }
        }
        return list;
    }

    @Override
    public List<KeyWordTaskVO> listKeyWordTask() {
        return taskMapper.listKeyWordTask();
    }

    @Override
    public TaskDto getTaskByKey(String search, String wxUserId) {
        TaskDto taskByKey = taskMapper.getTaskByKey(search);
        if (taskByKey != null) {
            taskByKey.setSubscribeState(taskSubscribeBiz.getSubscribeState(wxUserId, taskByKey.getTaskId()).getState());
        }
        return taskByKey;
    }

    @Override
    public List<LabelDto> listMaxDepLabel(Integer num) {
        if (null == num) {
            num = 10;
        }
        List<Long> depLabelIds = taskMapper.listMaxDepLabel(num);
        List<LabelDto> list = new ArrayList<>();
        if (!ListUtils.isEmpty(depLabelIds)) {
            depLabelIds.forEach(depLabelId -> {
                LabelDto labelDto = new LabelDto();
                labelDto.setDepLabelId(depLabelId);
                String labelName = ResponseHandleUtil.parseResponse(labelService.getLabelName(depLabelId), String.class);
                labelDto.setDepLabelName(labelName);
                list.add(labelDto);
            });
        }
        return list;
    }

    @Override
    public List<TaskDto> listTaskByKey4User(String wxUserId, String search) {
        //1根据关键词去查询关联任务ID集合
        //List<Long> taskIds = ResponseHandleUtil.parseList(pcloudKeywordService.getTimePlanByGuideKeyword(search),Long.class);
        List<Long> taskIds = new ArrayList<>();
        List<TaskDto> taskDtoList = taskMapper.listTaskByKey4User(search, taskIds);
        if (!ListUtils.isEmpty(taskDtoList)) {
            //封装用户订阅状态
            taskDtoList.forEach(taskDto -> {
                taskDto.setSubscribeState(taskSubscribeBiz.getSubscribeState(wxUserId, taskDto.getTaskId()).getState());
            });
        }
        return taskDtoList;
    }

    @Override
    public List<TaskDto> listTaskByIds4User(String wxUserId, List<Integer> taskIds) {
        List<TaskDto> taskDtoList = taskMapper.listTaskByIds(taskIds);
        if (!ListUtils.isEmpty(taskDtoList)) {
            //封装用户订阅状态
            taskDtoList.forEach(taskDto -> {
                taskDto.setSubscribeState(taskSubscribeBiz.getSubscribeState(wxUserId, taskDto.getTaskId()).getState());
            });
        }
        return taskDtoList;
    }

    @Override
    public List<TaskDto> listTaskByLabelIds4User(String wxUserId, Long labelId) {
        List<TaskDto> taskDtoList = taskMapper.listTaskByLabelId(labelId);
        if (!ListUtils.isEmpty(taskDtoList)) {
            //封装用户订阅状态
            taskDtoList.forEach(taskDto -> {
                taskDto.setSubscribeState(taskSubscribeBiz.getSubscribeState(wxUserId, taskDto.getTaskId()).getState());
            });
        }
        return taskDtoList;
    }

    @Override
    @ParamLog
    @Transactional(rollbackFor = Exception.class)
    public void finishTaskSend(Integer taskSendId) {
        TimeControlTaskSend timeControlTaskSend = timeControlTaskSendMapper.getById(taskSendId);
        if (null == timeControlTaskSend) {
            return;
        }
        if (!(YesOrNoEnums.YES.getValue().equals(timeControlTaskSend.getWorking()) && YesOrNoEnums.NO.getValue().equals(timeControlTaskSend.getCompleteState()))){
            LOGGER.info("状态不对，不能完成任务");
            return;
        }
        Integer taskItemId = timeControlTaskSend.getTaskItemId();
        String wxUserId = timeControlTaskSend.getWxUserId();
        TimeControlTaskSubscribe timeControlTaskSubscribe = taskSubscribeMapper.getById(timeControlTaskSend.getSubscribeId());
        String robotWxId = timeControlTaskSubscribe.getRobotWxId();
        GroupRobotDTO groupRobotDTO = wechatGroupConsr.getGroupRobotByWxId(robotWxId);
        String ip = weixinQrcodeBiz.getRobotIpByGeneration(groupRobotDTO.getVersion());
        List<TimeControlReplyMessage> replyMessages = replyMessageMapper.list4TaskItem(taskItemId, 1);
        sendReplyMessage(replyMessages, wxUserId, robotWxId, ip);
        timeControlTaskSendMapper.updateSendState(taskSendId, TaskSendStateEnum.FINISH_SEND.getState(), 1);

        //每次都要判断一下是否所有单项任务都完成。完成之后需要同步修改关注表里面完成状态
        Integer noCompletedItem = timeControlTaskSendMapper.getNoCompletedCount(timeControlTaskSend.getSubscribeId());
        if(noCompletedItem==0){
            taskSubscribeMapper.completedTaskById(timeControlTaskSend.getSubscribeId());
        }
        new Thread(() -> {
            //处理奖励信息
            handlePrize(timeControlTaskSubscribe, ip, timeControlTaskSend.getTaskItemId());
        }).start();
    }

    private void handlePrize(TimeControlTaskSubscribe timeControlTaskSubscribe, String ip, Integer taskItemId) {
        LOGGER.info("开始处理奖励信息");
        //先判断有无单次奖励
        TimeControlTaskPrize taskPrize = taskPrizeMapper.getByTaskItemId(taskItemId);
        if (null != taskPrize) {
            if (taskPrize.getHasApp().equals(YesOrNoEnums.YES.getValue()) ||  taskPrize.getHasCoupon().equals(YesOrNoEnums.YES.getValue()) ||
                    taskPrize.getHasCertificate().equals(YesOrNoEnums.YES.getValue())) {
                List<TimeControlPrizeItem> timeControlPrizeItems = taskPrizeItemMapper.listByPrizeId(taskPrize.getId());
                if (!ListUtils.isEmpty(timeControlPrizeItems)) {
                    LOGGER.info("开始发送单次奖励");
                    timeControlPrizeItems.forEach(timeControlPrizeItem -> {
                        sendMessage(timeControlPrizeItem, ip, timeControlTaskSubscribe.getWxUserId(), timeControlTaskSubscribe.getRobotWxId());
                    });
                }
            }
        }
        Integer taskId = timeControlTaskSubscribe.getTaskId();
        //判断是否到大累计奖励
        Integer completedCount = timeControlTaskSendMapper.getCompletedCount(timeControlTaskSubscribe.getId());
        TimeControlTaskPrize byTaskId = taskPrizeMapper.getByTaskId(taskId, TaskPrizeTypeEnum.GRAND_TOTAL.key);
        if (byTaskId != null && completedCount.equals(byTaskId.getTotalPrizeNum())) {
            List<TimeControlPrizeItem> timeControlPrizeItems = taskPrizeItemMapper.listByPrizeId(byTaskId.getId());
            if (!ListUtils.isEmpty(timeControlPrizeItems)) {
                LOGGER.info("开始发送累计奖励");
                timeControlPrizeItems.forEach(timeControlPrizeItem -> {
                    sendMessage(timeControlPrizeItem, ip, timeControlTaskSubscribe.getWxUserId(), timeControlTaskSubscribe.getRobotWxId());
                });
            }
        }
    }

    private void sendMessage(TimeControlPrizeItem timeControlPrizeItem, String ip, String wxUserId, String robotWxId) {
        String groupId = UUID.randomUUID().toString();
        if (timeControlPrizeItem.getPrizeType() == 1) {
            //优惠券
            SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
            sendTextMessageVO.setContent(timeControlPrizeItem.getCouponTitle() + "\n" + timeControlPrizeItem.getCouponUrl());
            sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
            sendTextMessageVO.setWxId(robotWxId);
            sendTextMessageVO.setAltId(robotWxId);
            sendTextMessageVO.setWxGroupId(wxUserId);
            sendTextMessageVO.setIp(ip);
            sendTextMessageVO.setIndex(0);
            sendTextMessageVO.setCounts(1);
            sendTextMessageVO.setMessageGroupId(groupId);
            sendTextMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
            wechatGroupConsr.sendMessage(JSON.toJSONString(sendTextMessageVO));;
        } else if (timeControlPrizeItem.getPrizeType() == 2) {
            //应用
            if (AppAndProductTypeEnum.APP.value.equals(timeControlPrizeItem.getServeType())) {
                AppDto appDto = appConsr.getBaseById(timeControlPrizeItem.getServeId());
                if (appDto != null) {
                    AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(appDto.getChannelId());
                    // 处理链接地址
                    String endUrl = timeControlPrizeItem.getLinkUrl() + "&wxId=" + wxUserId + "&robotWxId=" + robotWxId;
                    String linkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, endUrl);
                    String resultUrl = UrlUtils.getShortUrl4Own(linkUrl);
                    SendArticleMessageVO sendArticleMessageVO = new SendArticleMessageVO();
                    sendArticleMessageVO.setCode(1);
                    sendArticleMessageVO.setAltId(robotWxId);
                    sendArticleMessageVO.setDescription(appDto.getTypeName());
                    sendArticleMessageVO.setWxGroupId(wxUserId);
                    sendArticleMessageVO.setLinkUrl(resultUrl);
                    sendArticleMessageVO.setPicUrl(appDto.getSquareImg());
                    sendArticleMessageVO.setTitle(appDto.getTitle());
                    sendArticleMessageVO.setIp(ip);
                    sendArticleMessageVO.setIndex(0);
                    sendArticleMessageVO.setCounts(1);
                    sendArticleMessageVO.setMessageGroupId(groupId);
                    sendArticleMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                    wechatGroupConsr.sendMessage(JSON.toJSONString(sendArticleMessageVO));
                }
            }
        } else if (timeControlPrizeItem.getPrizeType() == 3) {
            String s = taskPrizeBiz.downloadUrl(timeControlPrizeItem, wxUserId);
            if (null != s) {
                SendFileVO sendFileVO = new SendFileVO();
                sendFileVO.setFileUrl(s);
                sendFileVO.setFileName(DateUtils.today() + "-任务奖状" + ".jpg");
                sendFileVO.setIp(ip);
                sendFileVO.setAltId(robotWxId);
                sendFileVO.setWxId(wxUserId);
                sendFileVO.setIndex(0);
                sendFileVO.setCounts(1);
                sendFileVO.setMessageGroupId(groupId);
                sendFileVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendFileVO));
            }
        }
    }

    @Override
    public TaskDto getTaskByIdAndWxUserId(Integer relSkillId, String wxUserId) {
        return taskMapper.getTaskByIdAndWxUserId(relSkillId,wxUserId);
    }

    @Override
    public void sendReplyMessage(List<TimeControlReplyMessage> replyMessages, String wxUserId, String robotWxId, String ip) {
        String groupId = UUID.randomUUID().toString();
        int counts = replyMessages.size();
        if (!ListUtils.isEmpty(replyMessages)) {
            LOGGER.info("开始发送完成信息");
            for (int i = 0; i < replyMessages.size(); i++) {
                TimeControlReplyMessage replyMessage = replyMessages.get(i);
                if (replyMessage != null) {
                    Integer replyType = replyMessage.getReplyType();
                    if (ReplyTypeEnum.TEXT.value.equals(replyType)) {
                        // 发送文本
                        SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
                        sendTextMessageVO.setContent(replyMessage.getContent());
                        sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                        sendTextMessageVO.setWxId(robotWxId);
                        sendTextMessageVO.setAltId(robotWxId);
                        sendTextMessageVO.setWxGroupId(wxUserId);
                        sendTextMessageVO.setIp(ip);
                        sendTextMessageVO.setIndex(i);
                        sendTextMessageVO.setCounts(counts);
                        sendTextMessageVO.setMessageGroupId(groupId);
                        sendTextMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                        wechatGroupConsr.sendMessage(JSON.toJSONString(sendTextMessageVO));;
                    } else if (ReplyTypeEnum.IMAGE.value.equals(replyType)) {
                        // 发送图片
                        SendPicMessageVO sendPicMessageVO = new SendPicMessageVO();
                        sendPicMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                        sendPicMessageVO.setAltId(robotWxId);
                        sendPicMessageVO.setWxGroupId(wxUserId);
                        sendPicMessageVO.setPicUrl(replyMessage.getPicUrl());
                        sendPicMessageVO.setIp(ip);
                        sendPicMessageVO.setIndex(i);
                        sendPicMessageVO.setCounts(counts);
                        sendPicMessageVO.setMessageGroupId(groupId);
                        sendPicMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                        wechatGroupConsr.sendMessage(JSON.toJSONString(sendPicMessageVO));
                    } else if (ReplyTypeEnum.APP.value.equals(replyType)) {
                        Long serveId = replyMessage.getServeId();
                        String completeLink = null;
                        if (AppAndProductTypeEnum.APP.value.equals(replyMessage.getServeType())) {
                            AppDto appDto = appConsr.getBaseById(serveId);
                            if (appDto != null) {
                                Long channelId = appDto.getChannelId();
                                AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(channelId);
                                // 处理链接地址
                                completeLink = ServeLinkUtils.getCompleteLink(replyMessage.getLinkUrl(), String.valueOf(accountSettingDto.getAccountSettingId()), accountSettingDto.getProtocol(),
                                        accountSettingDto.getDomain(), accountSettingDto.getFirstDomain(), String.valueOf(accountSettingDto.getRandom()));
                            }
                        } else {
                            completeLink = replyMessage.getLinkUrl();
                        }
                        SendArticleMessageVO sendArticleMessageVO = new SendArticleMessageVO();
                        sendArticleMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                        sendArticleMessageVO.setAltId(robotWxId);
                        sendArticleMessageVO.setDescription(replyMessage.getDescription());
                        sendArticleMessageVO.setWxGroupId(wxUserId);
                        completeLink = completeLink + "&wxId=" +wxUserId +"&robotWxId=" +robotWxId;
                        sendArticleMessageVO.setLinkUrl(completeLink);
                        sendArticleMessageVO.setPicUrl(replyMessage.getPicUrl());
                        sendArticleMessageVO.setTitle(replyMessage.getContent());
                        sendArticleMessageVO.setIp(ip);
                        sendArticleMessageVO.setIndex(i);
                        sendArticleMessageVO.setCounts(counts);
                        sendArticleMessageVO.setMessageGroupId(groupId);
                        sendArticleMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                        wechatGroupConsr.sendMessage(JSON.toJSONString(sendArticleMessageVO));
                    } else if (ReplyTypeEnum.RESOURCE.value.equals(replyType)) {
                        SendFileVO sendFileVO = new SendFileVO();
                        Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(replyMessage.getResourceId()));
                        ResourceDTO resourceDTO = map.get(replyMessage.getResourceId());
                        if (resourceDTO != null) {
                            sendFileVO.setFileUrl(resourceDTO.getFileUrl());
                            String fileName = resourceDTO.getResourceName();
                            String fileType = resourceDTO.getFileType();
                            log.info("fileName=" + fileName + "+fileType+" + fileType);
                            if (fileName.contains(fileType)) {//去掉后缀
                                fileName = fileName.substring(0, fileName.indexOf(fileType) - 1);
                            }
                            log.info("fileName=" + fileName);
                            sendFileVO.setFileName(fileName);
                        }
                        sendFileVO.setIp(ip);
                        sendFileVO.setAltId(robotWxId);
                        sendFileVO.setWxId(wxUserId);
                        sendFileVO.setCode(SendMessageTypeEnum.SELF.getCode());
                        sendFileVO.setIndex(i);
                        sendFileVO.setCounts(counts);
                        sendFileVO.setMessageGroupId(groupId);
                        sendFileVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                        wechatGroupConsr.sendMessage(JSON.toJSONString(sendFileVO));
                    }else if (ReplyTypeEnum.LINK.value.equals(replyType)) {
                        SendArticleMessageVO sendArticleMessageVO = new SendArticleMessageVO();
                        sendArticleMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                        sendArticleMessageVO.setAltId(robotWxId);
                        sendArticleMessageVO.setDescription(replyMessage.getDescription());
                        sendArticleMessageVO.setWxGroupId(wxUserId);
                        sendArticleMessageVO.setLinkUrl(replyMessage.getLinkUrl());
                        sendArticleMessageVO.setPicUrl(replyMessage.getPicUrl());
                        sendArticleMessageVO.setTitle(replyMessage.getContent());
                        sendArticleMessageVO.setIp(ip);
                        sendArticleMessageVO.setIndex(i);
                        sendArticleMessageVO.setCounts(counts);
                        sendArticleMessageVO.setMessageGroupId(groupId);
                        sendArticleMessageVO.setRobotProcessType(RobotProcessTypeEnum.TIME_CONTROL);
                        wechatGroupConsr.sendMessage(JSON.toJSONString(sendArticleMessageVO));
                    }
                }
            }
        }
    }

    @Override
    public Integer copyTaskItem(Integer taskItemId) {
        TimeControlTaskItem timeControlTaskItem = taskItemMapper.selectByPrimaryKey(taskItemId);
        if (null != timeControlTaskItem) {
            timeControlTaskItem.setId(null);
            timeControlTaskItem.setStartDay(timeControlTaskItem.getStartDay() + 1);
            taskItemMapper.insert(timeControlTaskItem);
            Integer newItemId = timeControlTaskItem.getId();
            List<TimeControlReplyMessage> list = replyMessageMapper.list4TaskItem(taskItemId,null);
            if (!ListUtils.isEmpty(list)) {
                list.forEach(replyMessage -> {
                    replyMessage.setTaskItemId(newItemId);
                });
                replyMessageMapper.batchInsert(list);
            }
            return newItemId;
        }
        return null;
    }

    @Override
    public void addTask4TimeControl() {
        try {
            String cronStr = "0 0 0 * * ?";
            String jobName = BookConstant.TIME_CONTROL_UPDATE_SEND;
            ScheduleJob job = new ScheduleJob();
            //定时器任务
            job.setJobName(jobName);
            //cron表达式
            job.setCronExpression(cronStr);
            //定时器分组
            job.setJobGroup("book");
            CallBackParam param = new CallBackParam();
            //service名称
            param.setBeanName("timeControlTaskService");
            //回调内部接口方法名称
            param.setMethodName("updateSendState4Week");
            //设置回调参数
            Map<String, Object> map = new HashMap<>();
            map.put("jobName", jobName);
            param.setParamMap(map);
            Map<String, Object> scheduleMap = new HashMap<>();
            scheduleMap.put("scheduleJob", job);
            scheduleMap.put("callBackParam", param);
            scheduleService.addCronJob(scheduleMap);
        } catch (SchedulerException | JsonParseException e) {
            log.info("【TaskBizImpl.createCronJob】创建定时任务失败", e);
        }
    }

    @Override
    @ParamLog("定时任务更新send表发送状态")
    public void updateSendState4Week() {
        timeControlTaskSendMapper.updateSendState4Week();
    }

    @Override
    @ParamLog("修改任务模板的发送方式")
    public void updateTaskSendType(TimeControlTask taskDto) {
        //由周转为天需将之前的周的定时任务删掉
        if (SendTypeEnum.SEND_DAY.state.equals(taskDto.getSendType())){
            deleteQuartz4TaskId(taskDto.getTaskId());
        }
        //删除之前的任务
        taskItemMapper.deleteByTaskId(taskDto.getTaskId());
        taskMapper.updateTaskSendType(taskDto);
    }

    private void deleteQuartz4TaskId(Integer taskId) {
        //同时删除定时任务
        List<TimeControlTaskItem> timeControlTaskItems = taskItemMapper.listByTaskId(taskId);
        if (ListUtils.isEmpty(timeControlTaskItems)){
            return;
        }
        List<Integer> taskItemIds = timeControlTaskItems.stream().map(TimeControlTaskItem::getId).collect(Collectors.toList());
        //删除周任务
        timeControlTaskItemWeekMapper.batchDelete(taskItemIds);
        taskItemIds.forEach(id ->{
            try {
                scheduleService.deleteJob( BookConstant.TIME_CONTROL_SEND + id, "book");
            } catch (Exception e) {
                log.error("删除定时任务失败,taskItemId+" + id);
            }
        });
    }

}
