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

import com.pcloud.book.base.exception.BookBizException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.WeixinQrcodeBiz;
import com.pcloud.book.guide.biz.PcloudGuideBiz;
import com.pcloud.book.mq.delay.DelayMessageSender;
import com.pcloud.book.pcloudkeyword.dao.PcloudRobotClassifyDao;
import com.pcloud.book.pcloudkeyword.dao.PcloudRobotDao;
import com.pcloud.book.pcloudkeyword.entity.PcloudRobot;
import com.pcloud.book.pcloudkeyword.entity.PcloudRobotClassify;
import com.pcloud.book.personalstage.biz.PersonalStageBiz;
import com.pcloud.book.personalstage.biz.PersonalStageJumpBiz;
import com.pcloud.book.personalstage.constant.PersonalStageConstant;
import com.pcloud.book.personalstage.dao.PersonalStageJumpDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpEmailDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpKeywordDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpLinkupDao;
import com.pcloud.book.personalstage.dao.PersonalStageUserDao;
import com.pcloud.book.personalstage.dto.LinkupDelayDTO;
import com.pcloud.book.personalstage.dto.PersonalStageJumpDto;
import com.pcloud.book.personalstage.dto.PersonalStageJumpKeywordDto;
import com.pcloud.book.personalstage.entity.PersonalStage;
import com.pcloud.book.personalstage.entity.PersonalStageJump;
import com.pcloud.book.personalstage.entity.PersonalStageJumpEmail;
import com.pcloud.book.personalstage.entity.PersonalStageJumpKeyword;
import com.pcloud.book.personalstage.entity.PersonalStageJumpLinkup;
import com.pcloud.book.personalstage.entity.PersonalStageUser;
import com.pcloud.book.personalstage.enums.JumpTypeEnum;
import com.pcloud.book.personalstage.enums.PersonalStageUserStateEnum;
import com.pcloud.book.personalstage.vo.request.BaseStageJumpRequestVO;
import com.pcloud.book.personalstage.vo.request.CreateStageJumpRequestVO;
import com.pcloud.book.personalstage.vo.request.UpdateStageJumpRequestVO;
import com.pcloud.book.util.common.YesOrNoEnums;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.core.biz.MessageBiz;
import com.pcloud.common.core.dto.SendEmailDto;
import com.pcloud.common.core.mq.DelayQueueDTO;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.DateNewUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.wechatgroup.group.dto.GroupRobotDTO;
import com.pcloud.wechatgroup.group.dto.GroupUserDTO;
import com.sdk.wxgroup.SendMessageTypeEnum;
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.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import java.util.HashMap;
import java.util.Map;

@Component("personalStageJumpBiz")
public class PersonalStageJumpBizImpl implements PersonalStageJumpBiz {

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

    @Autowired
    private PersonalStageBiz personalStageBiz;
    @Autowired
    private PersonalStageJumpDao personalStageJumpDao;
    @Autowired
    private PersonalStageJumpKeywordDao personalStageJumpKeywordDao;
    @Autowired
    private PersonalStageJumpEmailDao personalStageJumpEmailDao;
    @Autowired
    private PersonalStageJumpLinkupDao personalStageJumpLinkupDao;
    @Autowired
    private PersonalStageUserDao personalStageUserDao;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private WeixinQrcodeBiz weixinQrcodeBiz;
    @Autowired
    private PcloudRobotDao pcloudRobotDao;
    @Autowired
    private PcloudRobotClassifyDao pcloudRobotClassifyDao;
    @Autowired
    private MessageBiz messageBiz;
    @Autowired
    private PcloudGuideBiz pcloudGuideBiz;
    @Autowired
    private DelayMessageSender delayMessageSender;

    @Override
    @ParamLog("新增阶段跳转")
    @Transactional(rollbackFor = Exception.class)
    public void createPersonalStageJump(CreateStageJumpRequestVO vo) {
        //校验关键词是否重复
        if (!JumpTypeEnum.PAY_TRIGGER.key.equals(vo.getJumpType())){
            this.checkKeywords(vo.getKeywords(), vo.getPersonalStageId(), null);
        }
        if (vo.getOpenEmail()){
            this.checkEmail(vo.getEmails());
        }
        PersonalStageJump personalStageJump = CreateStageJumpRequestVO.valueToJumpEntity(vo);
        personalStageJumpDao.insert(personalStageJump);
        List<PersonalStageJumpKeyword> jumpKeywords = BaseStageJumpRequestVO.valueToJumpKeywords(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpKeywords)) {
            personalStageJumpKeywordDao.batchInsert(jumpKeywords);
        }
        List<PersonalStageJumpEmail> jumpEmails = BaseStageJumpRequestVO.valueToJumpEmails(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpEmails)) {
            personalStageJumpEmailDao.batchInsert(jumpEmails);
        }
        List<PersonalStageJumpLinkup> jumpLinkups = BaseStageJumpRequestVO.valueToJumpLinkups(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpLinkups)){
            personalStageJumpLinkupDao.batchInsert(jumpLinkups);
        }
    }

    @Override
    @ParamLog("获取跳转设置列表")
    public PageBeanNew getJumpList(Long personalStageId, Integer currentPage, Integer numPerPage) {
        if(!NumberUtil.isNumber(personalStageId) || personalStageId <= 0){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(), "personalStageId 值不能为空");
        }
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("personalStageId", personalStageId);
        PageBeanNew<PersonalStageJumpDto> pageBeanNew = personalStageJumpDao.listPageNew(new PageParam(currentPage, numPerPage), map, "getJumpList");
        List<PersonalStageJumpDto> recordList = pageBeanNew.getRecordList();
        if(ListUtils.isEmpty(recordList)){
            return pageBeanNew;
        }
        this.fillJumpKeywords(recordList);
        this.fillJumpEmails(recordList);
        this.fillJumpLinkups(recordList);
        return pageBeanNew;
    }

    @ParamLog("填充邮件")
    private void fillJumpEmails(List<PersonalStageJumpDto> recordList) {
        List<Long> jumpIds = recordList.stream().map(x -> x.getId()).collect(Collectors.toList());
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("jumpIds", jumpIds);
        List<PersonalStageJumpEmail> jumpEmails = personalStageJumpEmailDao.listBy(map);
        if(ListUtils.isEmpty(jumpEmails)){
            return;
        }
        Map<Long, List<PersonalStageJumpEmail>> mapJumpEmails = jumpEmails.stream().collect(Collectors.groupingBy(x -> x.getPersonalStageJumpId()));
        for (PersonalStageJumpDto jumpDto : recordList){
            jumpDto.setJumpEmails(mapJumpEmails.getOrDefault(jumpDto.getId(), Lists.newArrayList()));
        }
    }

    @ParamLog("填充跳转衔接语")
    private void fillJumpLinkups(List<PersonalStageJumpDto> recordList) {
        List<Long> jumpIds = recordList.stream().map(x -> x.getId()).collect(Collectors.toList());
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("jumpIds", jumpIds);
        List<PersonalStageJumpLinkup> linkups = personalStageJumpLinkupDao.listBy(map);
        if(ListUtils.isEmpty(linkups)){
            return;
        }
        Map<Long, List<PersonalStageJumpLinkup>> mapJumpLinkups = linkups.stream().collect(Collectors.groupingBy(x -> x.getPersonalStageJumpId()));
        for (PersonalStageJumpDto jumpDto : recordList){
            jumpDto.setJumpLinkups(mapJumpLinkups.getOrDefault(jumpDto.getId(), Lists.newArrayList()));
        }
    }

    @ParamLog("填充跳转关键字列表")
    private void fillJumpKeywords(List<PersonalStageJumpDto> recordList) {
        List<Long> jumpIds = recordList.stream().map(x -> x.getId()).collect(Collectors.toList());
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("jumpIds", jumpIds);
        List<PersonalStageJumpKeyword> keywords = personalStageJumpKeywordDao.listBy(map);
        if(ListUtils.isEmpty(keywords)){
            return;
        }
        Map<Long, List<PersonalStageJumpKeyword>> mapJumpKeyword = keywords.stream().collect(Collectors.groupingBy(x -> x.getPersonalStageJumpId()));
        for (PersonalStageJumpDto jumpDto : recordList){
            jumpDto.setJumpKeywords(mapJumpKeyword.getOrDefault(jumpDto.getId(), Lists.newArrayList()));
        }
    }

    @Override
    @ParamLog("修改跳转阶段")
    public void updatePersonalStageJump(UpdateStageJumpRequestVO vo) {
        //校验关键词是否重复
        this.checkKeywords(vo.getKeywords(), vo.getPersonalStageId(), vo.getPersonalStageJumpId());
        PersonalStageJump personalStageJump = UpdateStageJumpRequestVO.valueToJumpEntity(vo);
        personalStageJumpDao.update(personalStageJump);
        //删除原有的关键词
        personalStageJumpKeywordDao.deleteByJumpId(vo.getPersonalStageJumpId());
        //删除原有的邮件地址
        personalStageJumpEmailDao.deleteByJumpId(vo.getPersonalStageJumpId());
        //删除原有的衔接语
        personalStageJumpLinkupDao.deleteByJumpId(vo.getPersonalStageJumpId());
        List<PersonalStageJumpKeyword> jumpKeywords = BaseStageJumpRequestVO.valueToJumpKeywords(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpKeywords)){
            personalStageJumpKeywordDao.batchInsert(jumpKeywords);
        }
        List<PersonalStageJumpEmail> jumpEmails = BaseStageJumpRequestVO.valueToJumpEmails(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpEmails)){
            personalStageJumpEmailDao.batchInsert(jumpEmails);
        }
        List<PersonalStageJumpLinkup> jumpLinkups = BaseStageJumpRequestVO.valueToJumpLinkups(vo, personalStageJump.getId());
        if (!ListUtils.isEmpty(jumpLinkups)){
            personalStageJumpLinkupDao.batchInsert(jumpLinkups);
        }
    }

    @ParamLog("校验跳转关键词")
    private void checkKeywords(List<String> keywords, Long personalStageId, Long personalStageJumpId) {
        if (ListUtils.isEmpty(keywords)){
            throw new BookBizException(BookBizException.ERROR, "跳转关键词不能为空");
        }
        List<String> words = keywords.stream().distinct().collect(Collectors.toList());
        if (keywords.size() != words.size()) {
            throw new BookBizException(BookBizException.ERROR, "跳转关键词不能重复");
        }
        PersonalStageJumpKeyword personalStageJumpKeyword = personalStageJumpKeywordDao.getStageKeywordByKeywords(keywords, personalStageId);
        if (null != personalStageJumpKeyword) {
            if (null == personalStageJumpId
                    || !personalStageJumpId.equals(personalStageJumpKeyword.getPersonalStageJumpId())) {
                //如果personalStageJumpId为空，则为新增时校验,否则为修改时校验
                throw new BookBizException(BookBizException.ERROR, "跳转关键词不能重复");
            }
        }
    }

    @ParamLog("校验邮件地址")
    private void checkEmail(List<String> emails){
        if (ListUtils.isEmpty(emails)){
            throw new BookBizException(BookBizException.ERROR, "邮件地址不能为空");
        }
        List<String> fEmail = emails.stream().filter(e -> !StringUtil.isEmpty(e)).collect(Collectors.toList());
        if (ListUtils.isEmpty(fEmail) || emails.size() != fEmail.size()){
            throw new BookBizException(BookBizException.ERROR, "邮件地址不能为空");
        }
    }

    @Override
    @ParamLog("根据id获取跳转对象")
    public PersonalStageJumpDto getJump(Long jumpId) {
        if(!NumberUtil.isNumber(jumpId) || jumpId <= 0){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(), "jumpId 值不能为空");
        }
        PersonalStageJumpDto jumpDto = personalStageJumpDao.getDtoById(jumpId);
        if(jumpDto == null){
            jumpDto = new PersonalStageJumpDto();
            jumpDto.setJumpKeywords(Lists.newArrayList());
            jumpDto.setJumpLinkups(Lists.newArrayList());
            return jumpDto;
        }
        this.fillJumpKeywords(Lists.newArrayList(jumpDto));
        this.fillJumpEmails(Lists.newArrayList(jumpDto));
        this.fillJumpLinkups(Lists.newArrayList(jumpDto));
        return jumpDto;
    }

    @Override
    @ParamLog("删除跳转")
    public void deleteJump(Long jumpId) {
        if(!NumberUtil.isNumber(jumpId) || jumpId <= 0){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(), "jumpId 值不能为空");
        }
        // 删除跳转
        personalStageJumpDao.deleteById(jumpId);
        // 删除关键字
        personalStageJumpKeywordDao.deleteByJumpId(jumpId);
        // 删除邮件
        personalStageJumpEmailDao.deleteByJumpId(jumpId);
    }

    @Override
    @ParamLog("开启关闭邮件提醒")
    public Long updateEmailStatus(Long jumpId, Integer openEmail) {
        if(!NumberUtil.isNumber(jumpId) || jumpId <= 0){
            throw new BizException(BizException.PARAM_IS_NULL.getCode(), "jumpId 值不能为空");
        }
        PersonalStageJump jump = new PersonalStageJump();
        jump.setId(jumpId);
        jump.setOpenEmail(YesOrNoEnums.YES.getValue().equals(openEmail));
        return personalStageJumpDao.update(jump);
    }

    /**
     *
     * @param userWxId
     * @param robotWxId
     * @param content
     * @return  false:未能跳转到下个阶段，需要后续的其它处理；
     *          true:命中关键字，已经跳转到下个阶段，无需后续处理；
     */
    @Override
    @ParamLog("处理用户阶段跳转逻辑")
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public Boolean handlePersonalStageJump(String userWxId, String robotWxId, String content, JumpTypeEnum jumpTypeEnum) {
        // 查询用户的当前状态信息
        PersonalStageUser currentStageUser = personalStageUserDao.getLast(userWxId, robotWxId, null);
        // 如果用户没有阶段状态，则不处理
        if(currentStageUser == null || currentStageUser.getId() <= 0) {
            return false;
        }
        // TODO 判断消息的阶段是否和用户当前阶段匹配，如果不匹配需要当做已处理状态返回，以免触发后续其它操作
        //  (此操作需要建立在用户的消息有阶段id的情况下)
        // if(personalStageId != currentStageUser.getPersonalStageId()) { return true;  }
        // 查询命中关键字跳转下一阶段的id
        PersonalStageJumpKeywordDto jumpKeywordDto = personalStageJumpKeywordDao.getByKeyword(currentStageUser.getPersonalStageId(), content, jumpTypeEnum.key);
        if(null == jumpKeywordDto || StringUtil.isEmpty(jumpKeywordDto.getKeyword())){
            // 未能命中关键词
            return false;
        }
        // 如果下一个阶段是空，则已完成
        if(null == jumpKeywordDto.getAfterPersonalStageId() || jumpKeywordDto.getAfterPersonalStageId() <=0){
            // 更新到完成状态
            updateStageToComplete(currentStageUser);
            return true;
        }
        GroupRobotDTO groupRobotDTO = wechatGroupConsr.getGroupRobotByWxId(robotWxId);
        String ip = weixinQrcodeBiz.getRobotIpByGeneration(groupRobotDTO.getVersion());
        // 发送邮件
        sendEmail(userWxId, robotWxId, content, jumpKeywordDto);
        // 将用户置为下个阶段
        PersonalStageUser nextPersonalStageUser = personalStageBiz.nextStageAddStageUserAndWakeupDelay(robotWxId, userWxId, ip, jumpKeywordDto.getAfterPersonalStageId());
        // 发送内容衔接语
        sendJumpLinkups(userWxId, robotWxId, ip, jumpKeywordDto.getPersonalStageJumpId(),nextPersonalStageUser.getId());
        // 停止发送引导语
        pcloudGuideBiz.stopPcloudGuidePush(robotWxId, userWxId);
        return true;
    }

    @ParamLog("处理衔接语跳转延时")
    @Override
    public void dealDelayLinkup(DelayQueueDTO dto) {
        LinkupDelayDTO linkupDelayDTO=(LinkupDelayDTO)dto.getMsg();
        PersonalStageJumpLinkup jumpLinkup = personalStageJumpLinkupDao.getById(linkupDelayDTO.getPersonalStageJumpLinkupId());
        if (jumpLinkup==null){
            LOGGER.info("没有该跳转衔接语！");
            return;
        }
        SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
        sendTextMessageVO.setContent(personalStageBiz.replaceProjectProgressUrl(jumpLinkup.getLinkupContent(),linkupDelayDTO.getRobotId(),linkupDelayDTO.getWxId(),linkupDelayDTO.getPersonalStageUserId()));
        sendTextMessageVO.setAltId(linkupDelayDTO.getRobotId());
        sendTextMessageVO.setWxGroupId(dto.getKey());
        sendTextMessageVO.setIp(linkupDelayDTO.getIp());
        sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
        WxGroupSDK.sendTextMessage(sendTextMessageVO);
    }

    @ParamLog("发送阶段跳转邮件")
    private void sendEmail(String userWxId, String robotWxId, String content, PersonalStageJumpKeywordDto jumpKeywordDto) {
        try {
            List<PersonalStageJumpEmail> jumpEmails = personalStageJumpEmailDao.getByJumpId(jumpKeywordDto.getPersonalStageJumpId());
            if(ListUtils.isEmpty(jumpEmails)){
                return;
            }
            GroupUserDTO wxUserInfo = wechatGroupConsr.getWxUserInfoByWxUserId(userWxId);
            if(wxUserInfo==null){
                LOGGER.info("未找到用户信息，无法发送阶段跳转邮件");
            }
            PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotWxId);
            PcloudRobotClassify robotClassify = pcloudRobotClassifyDao.getById(pcloudRobot.getRobotType().longValue());
            if (robotClassify == null|| robotClassify.getKeywordClassifyId() == null){
                LOGGER.info("小号分类id为空，无法发送阶段跳转邮件");
                return;
            }
            PersonalStage personalStage = personalStageBiz.getPersonalStage(jumpKeywordDto.getAfterPersonalStageId());
            if (personalStage == null || StringUtil.isEmpty(personalStage.getName())){
                LOGGER.info("未找到阶段信息，无法发送阶段跳转邮件");
                return;
            }
            for (PersonalStageJumpEmail email : jumpEmails){
                sendStageChangeEmail(email.getEmail(), content, wxUserInfo.getNickName(), userWxId, robotClassify.getClassifyName(), pcloudRobot.getUniqueNumber(), robotWxId, personalStage.getName());
            }
        } catch (Exception e){
            LOGGER.info("阶段跳转邮件发送失败：" + e.getMessage(), e);
        }
    }

    /**
     * 发送阶段流转邮件
     * @param toEmail 接收人邮件
     * @param customizedService 定制服务需求（即触发阶段流转的关键词）
     * @param nickname 读者昵称
     * @param wxUserId 读者ID
     * @param robotClassifyName 小号分类名称
     * @param robotNumber 小号编号
     * @param robotId 小号ID
     * @param afterStageName 流转后阶段名称
     */
    public void sendStageChangeEmail(String toEmail, String customizedService, String nickname, String wxUserId,
                                     String robotClassifyName, String robotNumber, String robotId, String afterStageName) {
        try {
            SendEmailDto sendEmailDto = new SendEmailDto();
            sendEmailDto.setToEmail(toEmail);
            sendEmailDto.setTypeCode("stage_change_notice");
            Map<String, Object> content = new HashMap<>();
            content.put("customizedService", customizedService);
            content.put("nickname", nickname);
            content.put("wxUserId", wxUserId);
            content.put("robotClassifyName", robotClassifyName);
            content.put("robotNumber", robotNumber);
            content.put("robotId", robotId);
            content.put("afterStageName", afterStageName);
            content.put("time", DateNewUtils.getLongDateStr());
            sendEmailDto.setContent(content);
            messageBiz.sendEmail(sendEmailDto);
        } catch (Exception e) {
            LOGGER.error("发送阶段流转邮件出错：" + e.getMessage(), e);
        }
    }

    @ParamLog("发送内容衔接语")
    private void sendJumpLinkups(String userWxId, String robotWxId, String ip, Long jumpId, Long personalStageUserId) {
        List<PersonalStageJumpLinkup> linkups = personalStageJumpLinkupDao.getByJumpId(jumpId);
        if(ListUtils.isEmpty(linkups)){
            return;
        }
        for (PersonalStageJumpLinkup jumpLinkup : linkups){
            if (jumpLinkup.getToStageStartTime()!=null&&jumpLinkup.getToStageStartTime()>0){
                LinkupDelayDTO linkupDelayDTO=new LinkupDelayDTO();
                linkupDelayDTO.setPersonalStageJumpLinkupId(jumpLinkup.getId());
                linkupDelayDTO.setRobotId(robotWxId);
                linkupDelayDTO.setWxId(userWxId);
                linkupDelayDTO.setIp(ip);
                linkupDelayDTO.setPersonalStageUserId(personalStageUserId);
                DelayQueueDTO delayQueueDTO = DelayQueueDTO.builder().key(userWxId).type(PersonalStageConstant.PERSONALSTAGE_DELAY_LINKUP).msg(linkupDelayDTO).timeout(jumpLinkup.getToStageStartTime()*1000).build();
                delayMessageSender.send(delayQueueDTO);
                LOGGER.info("增加跳转衔接语延时"+delayQueueDTO.toString());
            }else {
                SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
                sendTextMessageVO.setContent(personalStageBiz.replaceProjectProgressUrl(jumpLinkup.getLinkupContent(),robotWxId,userWxId,personalStageUserId));
                sendTextMessageVO.setAltId(robotWxId);
                sendTextMessageVO.setWxGroupId(userWxId);
                sendTextMessageVO.setIp(ip);
                sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                WxGroupSDK.sendTextMessage(sendTextMessageVO);
            }
        }
    }

    @ParamLog("更新到完成状态")
    private void updateStageToComplete(PersonalStageUser currentStageUser) {
        PersonalStageUser updateStageUser = new PersonalStageUser();
        updateStageUser.setId(currentStageUser.getId());
        updateStageUser.setState(PersonalStageUserStateEnum.FINISH.value);
        updateStageUser.setUpdateTime(new Date());
        personalStageUserDao.update(updateStageUser);
    }
}
