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

import com.pcloud.book.adnews.biz.AdNewsBiz;
import com.pcloud.book.adnews.check.AdNewsCheck;
import com.pcloud.book.adnews.dao.*;
import com.pcloud.book.adnews.entity.*;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.WeixinQrcodeBiz;
import com.pcloud.book.group.dao.GroupQrcodeDao;
import com.pcloud.book.group.dto.BookWxQrcodeDTO;
import com.pcloud.book.group.dto.GroupQrcodeFoAdDTO;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.facade.quartz.entity.CallBackParam;
import com.pcloud.facade.quartz.entity.ScheduleJob;
import com.pcloud.facade.quartz.service.ScheduleService;
import com.sdk.wxgroup.SendTextMessageVO;
import com.sdk.wxgroup.WxGroupSDK;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author ruansiyuan
 * @Date 2019/7/17 15:02
 **/
@Component("adNewsBiz")
public class AdNewsBizImpl implements AdNewsBiz {

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

    @Autowired
    private AdNewsCheck adNewsCheck;
    @Autowired
    private AdNewsSetDao adNewsSetDao;
    @Autowired
    private AdNewsGroupDao adNewsGroupDao;
    @Autowired
    private ScheduleService scheduleService;
    @Autowired
    private GroupQrcodeDao groupQrcodeDao;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private AdNewsChooseDao adNewsChooseDao;
    @Autowired
    private AdNewsDao adNewsDao;
    @Autowired
    private AdNewsGroupRecordDao adNewsGroupRecordDao;
    @Autowired
    private WeixinQrcodeBiz weixinQrcodeBiz;

    private static final String AD_MORNING_NEWS_SCHEDULE_PRE = "AD_MORNING_NEWS_SCHEDULE_";

    private static final String AD_EVENING_NEWS_SCHEDULE_PRE = "AD_EVENING_NEWS_SCHEDULE_";

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("新增早晚报设置")
    @Override
    public Long createAdNewsSet(AdNewsSet adNewsSet) {
        adNewsCheck.createAdNewsSetCheck(adNewsSet);
        //新增之前判断是否有记录
        AdNewsSet adNewsSetOld=adNewsSetDao.getByPartyId(adNewsSet.getCreateUser());
        if (adNewsSetOld!=null){
            throw new BookBizException(BookBizException.ERROR,"不可重复创建！");
        }
        adNewsSetDao.insert(adNewsSet);
        buildAdNewsGroups(adNewsSet, adNewsSet.getCreateUser());
        adNewsGroupDao.batchInsert(adNewsSet.getAdNewsGroups());
        //创建定时任务
        buildAdNewsSh(adNewsSet);
        return adNewsSet.getId();
    }

    @ParamLog("创建编辑端早晚报定时任务")
    private void buildAdNewsSh(AdNewsSet adNewsSet) {
        if (adNewsSet.getHasMorningOpen()) {
            //早报定时任务
            createAdNewsSch(adNewsSet.getId(), adNewsSet.getMorningTime(), AD_MORNING_NEWS_SCHEDULE_PRE + adNewsSet.getId());
        }
        if (adNewsSet.getHasEveningOpen()) {
            //晚报定是任务
            createAdNewsSch(adNewsSet.getId(), adNewsSet.getEveningTime(), AD_EVENING_NEWS_SCHEDULE_PRE + adNewsSet.getId());
        }
    }

    @ParamLog("创建编辑早晚报定时任务")
    private void createAdNewsSch(Long adNewsSetId, String time, String jobName) {
        String cron;
        try {
            int hour = Integer.parseInt(time.substring(0, 2));
            int minute = Integer.parseInt(time.substring(3, 5));
            int second = Integer.parseInt(time.substring(6, 8));
            cron = second + " " + minute + " " + hour + " * * ?";
        } catch (Exception e) {
            throw new BookBizException(BookBizException.ERROR, "时间格式错误");
        }
        ScheduleJob scheduleJob = new ScheduleJob();
        scheduleJob.setJobGroup("book");
        scheduleJob.setJobName(jobName);
        scheduleJob.setCronExpression(cron);
        CallBackParam callBackParam = new CallBackParam();
        callBackParam.setMethodName("sendAdNews");
        callBackParam.setBeanName("adNewsService");
        Map<String, Object> paramMap = new HashMap<>();
        //定时任务调用时用到的参数
        paramMap.put("adNewsSetId", adNewsSetId);
        callBackParam.setParamMap(paramMap);
        Map<String, Object> scheduleMap = new HashMap<>();
        scheduleMap.put("scheduleJob", scheduleJob);
        scheduleMap.put("callBackParam", callBackParam);
        try {
            scheduleService.addCronJob(scheduleMap);
        } catch (Exception e) {
            LOGGER.error("设置定时任务失败" + e.getMessage(), e);
            throw new BookBizException(BookBizException.ERROR, "定时任务设置失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("修改早晚报设置")
    @Override
    public void updateAdNewsSet(AdNewsSet adNewsSet) {
        adNewsCheck.createAdNewsSetCheck(adNewsSet);
        Long adNewsSetId = adNewsSet.getId();
        AdNewsSet adNewsSetOld = adNewsSetDao.getById(adNewsSetId);
        if (adNewsSetOld == null) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "未找到该设置！");
        }
        //更新设置
        adNewsSetDao.update(adNewsSet);
        //删除之前旧的关联关系
        adNewsGroupDao.deleteByAdNewsSetId(adNewsSetId);
        //重新设置关联
        buildAdNewsGroups(adNewsSet, adNewsSet.getUpdateUser());
        adNewsGroupDao.batchInsert(adNewsSet.getAdNewsGroups());
        //删除旧的定时任务
        deleteAdNewsSch(AD_MORNING_NEWS_SCHEDULE_PRE + adNewsSet.getId());
        deleteAdNewsSch(AD_EVENING_NEWS_SCHEDULE_PRE + adNewsSet.getId());
        //设置新的定时任务
        buildAdNewsSh(adNewsSet);
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("发送编辑端早晚报")
    @Override
    public void sendAdNews(Long adNewsSetId) {
        AdNewsSet adNewsSet = adNewsSetDao.getById(adNewsSetId);
        if (adNewsSet == null) {
            return;
        }
        //查询关联
        List<AdNewsGroup> adNewsGroups = adNewsGroupDao.getListByAdNewsSetId(adNewsSetId);
        if (ListUtils.isEmpty(adNewsGroups)){
            return;
        }
        List<Long> classifyIds = adNewsGroups.stream().filter(s -> s.getClassifyId() != null).map(AdNewsGroup::getClassifyId).collect(Collectors.toList());
        //查询关联的群
        List<GroupQrcodeFoAdDTO> groupQrcodeFoAdDTOS = groupQrcodeDao.GroupQrcodeFoAdDTOSByClassifyIds(classifyIds);
        if (ListUtils.isEmpty(groupQrcodeFoAdDTOS)){
            return;
        }
        Integer sendCount = adNewsSet.getSendCount();
        //查询要发的记录
        Long adviserId = adNewsSet.getCreateUser();
        List<AdNews> adNewsList = adNewsDao.getNewsToSendBySetIdAndAdviser(adNewsSetId, adviserId, sendCount);
        if (ListUtils.isEmpty(adNewsList)){
            return;
        }
        //分成300一组
        List<String> contents = new ArrayList<>();
        String content = "";
        int i = 1;
        for (AdNews adNews : adNewsList) {
            String contentL = content + i + "." + adNews.getTitle() + adNews.getShortUrl() + "\n";
            if (contentL.length() >= 300) {
                contents.add(content);
                content = i + "." + adNews.getTitle() + adNews.getShortUrl() + "\n";
            } else {
                content = contentL;
            }
            if (i == adNewsList.size()) {
                contents.add(content);
            }
            i = i + 1;
        }
        String startContent = "";
        String endContent = "";
        if (adNewsSet.getHasStartContent()) {
            startContent = adNewsSet.getStartContent();
        }
        if (adNewsSet.getHasEndContent()) {
            endContent = adNewsSet.getEndContent();
        }
        //循环发送
        for (GroupQrcodeFoAdDTO groupQrcodeFoAdDTO:groupQrcodeFoAdDTOS){
            String weixinGroupId=groupQrcodeFoAdDTO.getWeixinGroupId();
            String robotId =wechatGroupConsr.getRobotIdByGroupId(weixinGroupId);
            if (StringUtil.isEmpty(robotId)){
                LOGGER.info("发送编辑端早晚报未找到小号"+weixinGroupId);
            }
            if (!StringUtil.isEmpty(startContent)) {
                //发送开场语
                sendAdNewsText(startContent, robotId, weixinGroupId);
            }
            //发送中间信息
            for (String text : contents) {
                //发送结束语
                sendAdNewsText(text, robotId, weixinGroupId);
            }
            if (!StringUtil.isEmpty(endContent)) {
                //发送结束语
                sendAdNewsText(endContent, robotId, weixinGroupId);
            }
        }
        //插入发送记录
        List<AdNewsGroupRecord> adNewsGroupRecords = new ArrayList<>();
        for (GroupQrcodeFoAdDTO groupQrcodeFoAdDTO : groupQrcodeFoAdDTOS) {
            for (AdNews adNews : adNewsList) {
                AdNewsGroupRecord adNewsGroupRecord = new AdNewsGroupRecord();
                adNewsGroupRecord.setAdNewsId(adNews.getId());
                adNewsGroupRecord.setAdNewsSetId(adNewsSetId);
                adNewsGroupRecord.setBookGroupId(groupQrcodeFoAdDTO.getBookGroupId());
                adNewsGroupRecord.setClassifyId(groupQrcodeFoAdDTO.getClassifyId());
                adNewsGroupRecord.setQrcodeId(groupQrcodeFoAdDTO.getQrcodeId());
                adNewsGroupRecord.setCreateUser(adviserId);
                adNewsGroupRecord.setUpdateUser(adviserId);
                adNewsGroupRecords.add(adNewsGroupRecord);
            }
        }
        adNewsGroupRecordDao.batchInsert(adNewsGroupRecords);
    }

    @ParamLog("获取编辑早晚报设置")
    @Override
    public AdNewsSet getAdNewsSet(Long partyId) {
        AdNewsSet adNewsSet = adNewsSetDao.getByPartyId(partyId);
        if (adNewsSet != null) {
            List<AdNewsGroup> adNewsGroups = adNewsGroupDao.getListByAdNewsSetId(adNewsSet.getId());
            adNewsSet.setAdNewsGroups(adNewsGroups);
            if (!ListUtils.isEmpty(adNewsGroups)) {
                List<Long> classifyIds = adNewsGroups.stream().filter(s -> s.getClassifyId() != null).map(AdNewsGroup::getClassifyId).collect(Collectors.toList());
                adNewsSet.setClassifyIds(classifyIds);
            }
        }
        return adNewsSet;
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("编辑添加选择的早晚报素材")
    @Override
    public void createAdNewsChooseBatch(List<Long> adNewsIds, Long partyId) {
        List<AdNewsChoose> adNewsChooses=new ArrayList<>();
        for (Long adNewsId:adNewsIds){
            AdNewsChoose adNewsChoose=new AdNewsChoose();
            adNewsChoose.setAdNewsId(adNewsId);
            adNewsChoose.setAdviserId(partyId);
            adNewsChoose.setCreateUser(partyId);
            adNewsChoose.setUpdateUser(partyId);
            adNewsChooses.add(adNewsChoose);
        }
        //校验重复添加
        Integer count = adNewsChooseDao.getCountByAdNewsIdsAndPartyId(adNewsIds, partyId);
        if (count > 0) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "请勿重复添加！");
        }
        adNewsChooseDao.batchInsert(adNewsChooses);
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("编辑移除选择的早晚报素材")
    @Override
    public void deleteAdNewsChoose(Long adNewsId, Long partyId) {
        adNewsChooseDao.deleteAdNewsChooseById(adNewsId,partyId);
    }

    @ParamLog("获取素材库列表")
    @Override
    public PageBeanNew<AdNews> getAdNewsList(String title, Long partyId, Integer currentPage, Integer numPerPage) {
        PageParam pageParam = new PageParam(currentPage, numPerPage);
        Map<String, Object> map = new HashMap<>();
        map.put("title", title);
        map.put("partyId",partyId);
        PageBeanNew<AdNews> pageBeanNew = adNewsDao.listPageNew(pageParam, map, "getAdNewsList");
        return pageBeanNew;
    }

    @ParamLog("获取编辑已选取的素材库列表")
    @Override
    public PageBeanNew<AdNews> getAdNewsChooseList(Long partyId, String title, Boolean hasUsed, Integer currentPage, Integer numPerPage) {
        PageParam pageParam = new PageParam(currentPage, numPerPage);
        Map<String, Object> map = new HashMap<>();
        map.put("title", title);
        map.put("partyId", partyId);
        map.put("hasUsed", hasUsed);
        PageBeanNew<AdNews> page = adNewsDao.listPageNew(pageParam, map, "getAdNewsChooseList");
        return page;
    }

    @ParamLog("发送消息")
    private void sendAdNewsText(String content, String robotId, String weixinGroupId) {
        SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
        sendTextMessageVO.setContent(content);
        sendTextMessageVO.setAltId(robotId);
        sendTextMessageVO.setGroupId(weixinGroupId);
        sendTextMessageVO.setIp(findIp(weixinGroupId));
        WxGroupSDK.sendTextMessage(sendTextMessageVO);
        LOGGER.info("发送编辑端早晚报" + sendTextMessageVO.toString());
    }

    @ParamLog("删除创建编辑早晚报定时任务")
    private void deleteAdNewsSch(String jobName) {
        try {
            scheduleService.deleteJob(jobName, "book");
        } catch (Exception e) {
            LOGGER.error("删除创建编辑早晚报定时任务失败");
        }
    }

    @ParamLog("构建早晚报关联")
    private void buildAdNewsGroups(AdNewsSet adNewsSet, Long partyId) {
        Long adNewsSetId = adNewsSet.getId();
        for (AdNewsGroup adNewsGroup : adNewsSet.getAdNewsGroups()) {
            adNewsGroup.setAdNewsSetId(adNewsSetId);
            adNewsGroup.setCreateUser(partyId);
            adNewsGroup.setUpdateUser(partyId);
        }
    }

    @ParamLog("获取ip")
    private String findIp(String wechatGroupId) {
        Map<String, BookWxQrcodeDTO> groupVersion = weixinQrcodeBiz.getGroupVersion(Collections.singletonList(wechatGroupId));
        String ip = Optional.ofNullable(groupVersion.get(wechatGroupId)).orElse(new BookWxQrcodeDTO()).getWechatGroupIp();
        return ip;
    }
}
