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

import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.BookGroupClassifyBiz;
import com.pcloud.book.group.biz.GroupQrcodeBiz;
import com.pcloud.book.group.dao.GroupQrcodeDao;
import com.pcloud.book.group.dto.GroupClassifyQrcodeDTO;
import com.pcloud.book.group.entity.GroupQrcode;
import com.pcloud.book.keywords.dao.BookKeywordDao;
import com.pcloud.book.keywords.dto.ReplyKeywordDTO;
import com.pcloud.book.riddle.biz.RiddleRecordBiz;
import com.pcloud.book.riddle.constants.RiddleConstant;
import com.pcloud.book.riddle.dao.RiddleDao;
import com.pcloud.book.riddle.dao.RiddleRecordDao;
import com.pcloud.book.riddle.dao.RiddleReplyDao;
import com.pcloud.book.riddle.dto.GroupRedisDTO;
import com.pcloud.book.riddle.dto.GroupRiddleDTO;
import com.pcloud.book.riddle.entity.Riddle;
import com.pcloud.book.riddle.entity.RiddleRecord;
import com.pcloud.book.riddle.enums.RiddleRecordStatusEnum;
import com.pcloud.book.riddle.enums.RiddleReplyTypeEnum;
import com.pcloud.book.riddle.redis.RiddleRedis;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.page.PageBeanNew;
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.pcloud.wechatgroup.group.dto.GroupUserDTO;
import com.pcloud.wechatgroup.message.dto.SendTextDTO;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @描述：猜谜记录
 * @作者：zhuyajie
 * @创建时间：18:20 2019/7/24
 * @版本：1.0
 */
@Component("riddleRecordBiz")
public class RiddleRecordBizImpl implements RiddleRecordBiz {
    private static final Logger logger = LoggerFactory.getLogger(RiddleRecordBizImpl.class);


    @Autowired
    private RiddleDao riddleDao;
    @Autowired
    private RiddleRecordDao riddleRecordDao;
    @Autowired
    private RiddleReplyDao riddleReplyDao;
    @Autowired
    private BookGroupClassifyBiz bookGroupClassifyBiz;
    @Autowired
    private BookKeywordDao bookKeywordDao;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private RiddleRedis riddleRedis;
    @Autowired
    private GroupQrcodeBiz groupQrcodeBiz;
    @Autowired
    private GroupQrcodeDao groupQrcodeDao;
    @Autowired
    private ScheduleService scheduleService;


    @Override
    @ParamLog("猜谜语游戏过程")
    public void riddleProcess(SendTextDTO sendTextDTO) {
        if (null == sendTextDTO || StringUtil.isEmpty(sendTextDTO.getTextContent())) {
            return;
        }
        if (!SendMessageTypeEnum.GROUP.getCode().equals(sendTextDTO.getCode())) {//非群消息不处理
            return;
        }
        String textContent = sendTextDTO.getTextContent().trim();
        String wxGroupId = sendTextDTO.getWechatGroupId();
        String wxUserId = sendTextDTO.getWechatUserId();
        String wxId = sendTextDTO.getWxId();
        String ip = sendTextDTO.getIp();
        GroupQrcode groupQrcode = groupQrcodeDao.getGroupQrcodeByGroupId(wxGroupId);
        if (null != groupQrcode) {
            if (!groupQrcode.getRiddleOpen()) {
                logger.info("微信群=" + wxGroupId + "没有开启猜谜语游戏权限");
                return;
            }
        }
        //历史记录
        RiddleRecord riddleRecord = riddleRecordDao.getLastRecordByWxGroupId(wxGroupId);
        //1该群猜谜语没有记录或已结束
        if (null == riddleRecord || (null != riddleRecord && RiddleRecordStatusEnum.end.getCode().equals(riddleRecord.getStatus()))) {
            Riddle currentRiddle = null;
            Integer finishCount = 0;
            if (null != riddleRecord) {
                currentRiddle = riddleDao.getById(riddleRecord.getRiddleId());
                finishCount = riddleRecord.getFinishCount() == null ? 0 : riddleRecord.getFinishCount();
                Integer correctCount = riddleRecordDao.getCorrectCountByGroup(wxGroupId, finishCount);
                if (correctCount == 180) {//结束前答对180道，通关次数+1
                    currentRiddle = null;
                    finishCount = finishCount + 1;
                }
            }
            //1.1关键词“猜谜语” ，游戏开启，计时
            if (textContent.equals("猜谜语")) {
                startGame(currentRiddle, wxGroupId, wxId, ip, finishCount);
            }
        }
        //2猜谜语进行中
        else if (null != riddleRecord && !RiddleRecordStatusEnum.end.getCode().equals(riddleRecord.getStatus())) {
            //2.1是关键词,不处理
            /*Boolean keyWord = false;
            GroupClassifyQrcodeDTO classifyQrcodeInfo = bookGroupClassifyBiz.getClassifyQrcodeInfo(wxGroupId);
            if (null != classifyQrcodeInfo) {
                ReplyKeywordDTO replyKeywordDTO = bookKeywordDao.getKeywordId(classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getBookGroupId(), textContent);
                if (null != replyKeywordDTO) {
                    keyWord = true;
                }
            }
            if (keyWord) {
                logger.info("该条信息为关键词，不处理，textContent=" + textContent);
                return;
            }*/
            Integer finishCount = riddleRecord.getFinishCount() == null ? 0 : riddleRecord.getFinishCount();
            Long riddleId = riddleRecord.getRiddleId();
            Riddle riddle = riddleDao.getById(riddleId);
            if (null == riddle) {
                logger.info("该条谜语不存在，riddleId+" + riddleId);
                return;
            }
            RiddleRecord insertRecord = new RiddleRecord();
            insertRecord.setRiddleId(riddleId);
            insertRecord.setWxGroupId(wxGroupId);
            insertRecord.setWxUserId(wxUserId);
            insertRecord.setFinishCount(finishCount);
            //2.2包含“结束”、“不想玩”，结束游戏
            if (textContent.contains("结束") || textContent.contains("不想玩") || textContent.contains("不玩了")) {
                endGame(insertRecord, wxGroupId, wxId, ip, riddle.getGrade(), finishCount);
                return;
            }
            //2.3中途参与,上一条答对了发送下一题,否则发送当前题目
            if (textContent.equals("猜谜语")) {
                midwayIn(riddle, riddleRecord.getCorrect(), wxGroupId, wxId, ip, wxUserId, finishCount);
                return;
            }
            //2.4不知道、提示、答案、正确答案,给提示语
            if (textContent.contains("不知道") || textContent.contains("提示") || textContent.contains("答案") || textContent.contains("正确答案")) {
                String before = "思考是件有趣的事哦，再想想吧。友情提示：可以问问其他人或者上网查询正确答案哦。";
                sendWeixinTextMessage(wxId, wxGroupId, before, ip, wxUserId);
                return;
            }
            //2.5判断答题对错
            judgeCorrcet(textContent, riddle, insertRecord, wxGroupId, wxId, ip, wxUserId, finishCount);
        }
    }

    @ParamLog("根据类型随机选取回复语")
    @Override
    public String getRandomReply(String type) {
        String reply = "";
        List<String> replyList = riddleReplyDao.getReplyByType(type);
        if (ListUtils.isEmpty(replyList)) {
            return reply;
        }
        int size = replyList.size();
        if (size == 1) {
            reply = replyList.get(0);
        } else if (size > 1) {
            Random random = new Random();
            reply = replyList.get(random.nextInt(size));
        }
        return reply;
    }

    @ParamLog("发送文本消息")
    public void sendWeixinTextMessage(String wxId, String wxGroupId, String content, String ip, String wxUserId) {
        SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
        sendTextMessageVO.setAltId(wxId);
        sendTextMessageVO.setWxGroupId(wxGroupId);
        if (!StringUtil.isEmpty(wxUserId)) {
            sendTextMessageVO.setAtId(wxUserId);
            GroupUserDTO groupUser = wechatGroupConsr.getWxUserInfoByWxUserId(wxUserId);
            if (null != groupUser && !StringUtil.isEmpty(groupUser.getNickName())) {
                content = "@" + groupUser.getNickName() + "。" + content;
            }
        }
        sendTextMessageVO.setContent(content);
        sendTextMessageVO.setIp(ip);
        logger.info("发送文本消息," + sendTextMessageVO);
        WxGroupSDK.sendTextMessage(sendTextMessageVO);
    }

    @ParamLog("发送下一题")
    public Boolean sendNextRiddle(Integer grade, Integer seq, String wxGroupId, String wxId, String ip,
                                  RiddleRecordStatusEnum statusEnum, String beforeContent, String wxUserId, Integer finishCount) {
        Riddle riddle = riddleDao.getRiddleByGradeAndSeq(grade, seq);
        if (null != riddle) {
            if (StringUtil.isEmpty(beforeContent)) {
                beforeContent = "接下来请听下一题：";
            }
            String sendText = beforeContent + riddle.getRiddleContent();
            sendWeixinTextMessage(wxId, wxGroupId, sendText, ip, wxUserId);
            //添加记录
            RiddleRecord insertRecord = new RiddleRecord();
            insertRecord.setRiddleId(riddle.getId());
            insertRecord.setMessageContent(sendText);
            insertRecord.setWxGroupId(wxGroupId);
            insertRecord.setWxUserId(wxId);
            insertRecord.setCorrect(null);
            insertRecord.setStatus(statusEnum.getCode());
            insertRecord.setFinishCount(finishCount);
            riddleRecordDao.insert(insertRecord);
            return true;
        } else {
            logger.info("本关题目没有下一题");
            return false;
        }
    }

    @Override
    public PageBeanNew<GroupRiddleDTO> listPage(Long partyId, Integer currentPage, Integer numPerPage, String name) {
        PageBeanNew<GroupRiddleDTO> pageBeanNew = groupQrcodeBiz.listPageRiddle(partyId, currentPage, numPerPage, name);
        if (null == pageBeanNew || ListUtils.isEmpty(pageBeanNew.getRecordList())) {
            return new PageBeanNew<>(currentPage, numPerPage, 0, new ArrayList<>());
        }
        for (GroupRiddleDTO riddleDTO : pageBeanNew.getRecordList()) {
            GroupRiddleDTO participateCountDTO = riddleRecordDao.getParticipateCount(riddleDTO.getWxGroupId());
            if (null != participateCountDTO) {
                riddleDTO.setUserNum(participateCountDTO.getUserNum() == 0 ? 0 : participateCountDTO.getUserNum());
                riddleDTO.setParticipateCount(participateCountDTO.getParticipateCount() == 0 ? 0 : participateCountDTO.getParticipateCount());
            }
            RiddleRecord riddleRecord = riddleRecordDao.getLastRecordByWxGroupId(riddleDTO.getWxGroupId());
            if (null != riddleRecord) {
                Riddle riddle = riddleDao.getById(riddleRecord.getRiddleId());
                riddleDTO.setGrade(riddle.getGrade());
                riddleDTO.setFinishCount(riddleRecord.getFinishCount());
                Integer correctCount = riddleRecordDao.getCorrectCountByGroup(riddleDTO.getWxGroupId(), riddleRecord.getFinishCount());
                riddleDTO.setCorrectCount(correctCount);
            }
        }
        return pageBeanNew;
    }

    @Override
    public void updateRiddleOpenStatus(Long qrcodeId, Boolean status) {
        groupQrcodeDao.updateRiddleOpenStatus(qrcodeId, status);
    }

    /**
     * 开启游戏
     */
    public void startGame(Riddle currentRiddle, String wxGroupId, String wxId, String ip, Integer finishCount) {
        //发送规则
        String reply = getRandomReply(RiddleReplyTypeEnum.rule.getCode());
        Integer correctCount = riddleRecordDao.getCorrectCountByGroup(wxGroupId, finishCount);
        if (null != currentRiddle) {
            reply = reply + "\n" + "目前处于第" + currentRiddle.getGrade() + "关，已猜对" + correctCount + "题，大家加油。";
        } else {
            reply = reply + "\n" + "目前处于第1关，已猜对0题，大家加油。";
        }
        sendWeixinTextMessage(wxId, wxGroupId, reply, ip, null);
        //发送题目，保存该题目
        if (null != currentRiddle) {//发送上次题目
            String content = "请听题：" + currentRiddle.getRiddleContent();
            sendWeixinTextMessage(wxId, wxGroupId, content, ip, null);
            RiddleRecord insertRecord = new RiddleRecord();
            insertRecord.setRiddleId(currentRiddle.getId());
            insertRecord.setMessageContent(content);
            insertRecord.setWxGroupId(wxGroupId);
            insertRecord.setWxUserId(wxId);
            insertRecord.setCorrect(null);
            insertRecord.setStatus(RiddleRecordStatusEnum.begin.getCode());
            insertRecord.setFinishCount(finishCount);
            riddleRecordDao.insert(insertRecord);

        } else {//从第一题开始
            sendNextRiddle(1, 0, wxGroupId, wxId, ip, RiddleRecordStatusEnum.begin, "请听题：", null, finishCount);
        }
        //开始5分钟/10s计时
        deleteJob(wxGroupId);
        addEndQuartzJob(wxGroupId, wxId, ip, wxId);
        riddleRedis.addUnderwayGroup(wxGroupId, wxId, ip);
    }

    /**
     * 结束游戏
     */
    public void endGame(RiddleRecord insertRecord, String wxGroupId, String wxId, String ip, Integer grade, Integer finishCount) {
        Integer correctCount = riddleRecordDao.getCorrectCountByGroup(wxGroupId, finishCount);
        String text = "好嘞，再见，爱你们哦。目前本群猜对谜语数" + correctCount + "道，处于第" + grade + "关，大家加油。";
        //发送结束语
        sendWeixinTextMessage(wxId, wxGroupId, text, ip, null);
        //保存结束记录
        insertRecord.setMessageContent(text);
        insertRecord.setStatus(RiddleRecordStatusEnum.end.getCode());
        insertRecord.setCorrect(null);
        riddleRecordDao.insert(insertRecord);
        deleteJob(wxGroupId);
        riddleRedis.deleteUnderwayGroup(wxGroupId);
    }

    /**
     * 中途进入
     */
    public void midwayIn(Riddle riddle, Boolean correct, String wxGroupId, String wxId, String ip, String wxUserId, Integer finishCount) {
        String beforeContent = getRandomReply(RiddleReplyTypeEnum.midway_in.getCode());
        if (null != correct && correct) {
            Boolean sendNext = sendNextRiddle(riddle.getGrade(), riddle.getSeq(), wxGroupId, wxId, ip, RiddleRecordStatusEnum.underway, beforeContent, wxUserId, finishCount);
            if (!sendNext) {//本关没有下一题
                if (riddle.getGrade() < 3) {//从下一关第一题开始
                    sendNextRiddle(riddle.getGrade() + 1, 0, wxGroupId, wxId, ip, RiddleRecordStatusEnum.underway, beforeContent, wxUserId, finishCount);
                } else {//3关都答完，从头开始
                    sendNextRiddle(1, 0, wxGroupId, wxId, ip, RiddleRecordStatusEnum.begin, beforeContent, wxUserId, finishCount + 1);
                }
            }
        } else {
            sendWeixinTextMessage(wxId, wxGroupId, beforeContent + riddle.getRiddleContent(), ip, wxUserId);
        }
        deleteJob(wxGroupId);
        addEndQuartzJob(wxGroupId, wxId, ip, wxId);
    }

    /**
     * 判断答题对错
     */
    public void judgeCorrcet(String textContent, Riddle riddle, RiddleRecord insertRecord, String wxGroupId, String wxId, String ip, String wxUserId, Integer finishCount) {
        if (StringUtil.isEmpty(textContent)) {
            logger.error("回复内容为空" + wxGroupId + "wxUserId" + wxUserId);
            return;
        }
        if (textContent.equals(riddle.getAnswer()) || textContent.equals(riddle.getOtherAnswer())) {//答对
            //答对文案
            String beforeContent = getRandomReply(RiddleReplyTypeEnum.correct.getCode());
            //保存答题记录
            insertRecord.setMessageContent(textContent);
            insertRecord.setCorrect(true);
            insertRecord.setStatus(RiddleRecordStatusEnum.underway.getCode());
            riddleRecordDao.insert(insertRecord);
            //发送下一题
            Boolean sendNext = sendNextRiddle(riddle.getGrade(), riddle.getSeq(), wxGroupId, wxId, ip, RiddleRecordStatusEnum.underway, beforeContent, wxUserId, finishCount);
            if (!sendNext) {//本关没有下一题
                if (riddle.getGrade() < 3) {//从下一关第一题开始
                    sendNextRiddle(riddle.getGrade() + 1, 0, wxGroupId, wxId, ip, RiddleRecordStatusEnum.underway, beforeContent, wxUserId, finishCount);
                } else {//3关都答完
                    sendWeixinTextMessage(wxId, wxGroupId, getRandomReply(RiddleReplyTypeEnum.finish_end.getCode()), ip, wxUserId);
                }
            }
            deleteJob(wxGroupId);
            addEndQuartzJob(wxGroupId, wxId, ip, wxUserId);
        } else if (riddle.getAnswer().contains(textContent) || textContent.contains(riddle.getAnswer())//部分答对
                || (!StringUtil.isEmpty(riddle.getOtherAnswer()) && textContent.contains(riddle.getOtherAnswer()))) {
            //保存答题记录
            insertRecord.setMessageContent(textContent);
            insertRecord.setCorrect(false);
            insertRecord.setStatus(RiddleRecordStatusEnum.underway.getCode());
            riddleRecordDao.insert(insertRecord);
            //发送部分答对文案
            String beforeContent = getRandomReply(RiddleReplyTypeEnum.partly_correct.getCode());
            sendWeixinTextMessage(wxId, wxGroupId, beforeContent, ip, null);

        } else {//答错
            //保存答题记录
            insertRecord.setMessageContent(textContent);
            insertRecord.setCorrect(false);
            insertRecord.setStatus(RiddleRecordStatusEnum.underway.getCode());
            riddleRecordDao.insert(insertRecord);
          /*  GroupRedisDTO dto = new GroupRedisDTO();
            dto.setIp(ip);
            dto.setWxId(wxId);
            dto.setWxGroupId(wxGroupId);
            this.timeSchedule(dto);*/
        }
    }

    /**
     * 自动结束
     */
    public void autoEnd(String wxGroupId, String wxId, String ip, String wxUserId) {
        RiddleRecord riddleRecord = riddleRecordDao.getLastRecordByWxGroupId(wxGroupId);
        if (null == riddleRecord) {
            logger.info("微信群=" + wxGroupId + "没有猜谜语游戏记录");
            return;
        }
        Long riddleId = riddleRecord.getRiddleId();
        Riddle riddle = riddleDao.getById(riddleId);
        if (null == riddle) {
            logger.info("谜语=" + riddleId + "不存在");
            return;
        }
        Integer grade = riddle.getGrade();
        Integer correctCount = riddleRecordDao.getCorrectCountByGroup(wxGroupId, riddleRecord.getFinishCount());
        String reply = getRandomReply(RiddleReplyTypeEnum.no_reply_end.getCode());
        String text = reply + "目前本群猜对谜语数" + correctCount + "道，处于第" + grade + "关。"
                + "\n" + "大家想玩记得回复关键词“猜谜语”，我等你们哦。";
        //发送结束语
        sendWeixinTextMessage(wxId, wxGroupId, text, ip, null);
        //保存结束记录
        RiddleRecord record = new RiddleRecord();
        record.setRiddleId(riddleId);
        record.setWxGroupId(wxGroupId);
        record.setWxUserId(wxUserId);
        record.setMessageContent(text);
        record.setStatus(RiddleRecordStatusEnum.end.getCode());
        record.setCorrect(null);
        record.setFinishCount(riddleRecord.getFinishCount());
        riddleRecordDao.insert(record);
        riddleRedis.deleteUnderwayGroup(wxGroupId);
    }


    /**
     * 添加定时任务-5分钟游戏自动结束
     */
    private void addEndQuartzJob(String wxGroupId, String wxId, String ip, String wxUserId) {
        ScheduleJob scheduleJob = new ScheduleJob();
        CallBackParam callBackParam = new CallBackParam();
        Map<String, Object> map = new HashMap<>();
        map.put("wxGroupId", wxGroupId);
        map.put("wxId", wxId);
        map.put("ip", ip);
        map.put("wxUserId", wxUserId);

        scheduleJob.setJobGroup(RiddleConstant.JOB_GROUP_RIDDLE);
        scheduleJob.setJobName(RiddleConstant.JOB_NAME_RIDDLE_EXPIRE + wxGroupId);
        scheduleJob.setStartTime(5);
        scheduleJob.setStartTimeFormat("mm");
        scheduleJob.setRepeatCount(0);
        scheduleJob.setIntervalTime(0);
        scheduleJob.setIntervalTimeFormat("mm");

        callBackParam.setBeanName("riddleService");
        callBackParam.setMethodName("riddleEndQuartz");
        callBackParam.setParamMap(map);
        Map<String, Object> scheduleMap = new HashMap<>();
        scheduleMap.put("scheduleJob", scheduleJob);
        scheduleMap.put("callBackParam", callBackParam);
        try {
            scheduleService.addSimpleJob(scheduleMap);
        } catch (Exception e) {
            logger.error("【猜谜语】添加定时任务失败" + e.getMessage(), e);
        }
    }

    /**
     * 删除定时任务-5分钟游戏自动结束
     */
    private void deleteJob(String wxGroupId) {
        try {
            scheduleService.deleteJob(RiddleConstant.JOB_NAME_RIDDLE_EXPIRE + wxGroupId, RiddleConstant.JOB_GROUP_RIDDLE);
        } catch (Exception e) {
            logger.error("【猜谜语】删除定时任务失败" + e.getMessage(), e);
        }
    }


    @Override
    @ParamLog("sendIncorrectMessage")
    public void sendIncorrectMessage(GroupRedisDTO groupRedisDTO) {
        if (null == groupRedisDTO) {
            return;
        }
        String wxGroupId = groupRedisDTO.getWxGroupId();
        RiddleRecord record = riddleRecordDao.getLastRecordByWxGroupId(wxGroupId);
        if (null == record) {
            return;
        }
        if (null != record.getCorrect() && record.getCorrect() == false) {
            logger.info("发送答错文案" + groupRedisDTO);
            //发送答错文案
            String beforeContent = this.getRandomReply(RiddleReplyTypeEnum.incorrect.getCode());
            this.sendWeixinTextMessage(groupRedisDTO.getWxId(), wxGroupId, beforeContent, groupRedisDTO.getIp(), null);
            //保存记录
            RiddleRecord insertRecord = new RiddleRecord();
            insertRecord.setRiddleId(record.getRiddleId());
            insertRecord.setWxGroupId(wxGroupId);
            insertRecord.setWxUserId(groupRedisDTO.getWxId());
            insertRecord.setMessageContent(beforeContent);
            insertRecord.setStatus(RiddleRecordStatusEnum.underway.getCode());
            insertRecord.setCorrect(null);
            insertRecord.setFinishCount(record.getFinishCount());
            riddleRecordDao.insert(insertRecord);
        }
    }


    /**
     * 10s后发送答错文案
     * @param dto
     */
    public void timeSchedule(GroupRedisDTO dto) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            public void run() {
                sendIncorrectMessage(dto);
            }
        }, 10000);
        try {
            //如果主线程不休眠一段时间，就执行了cancel方法，那么定时器还没来得及执行就会被关闭
            Thread.sleep(60*1000);
            timer.cancel();
        } catch (InterruptedException e) {
            logger.error("关闭线程定时器失败" + e.getMessage(), e);
        }
    }

}
