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

import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.message.TemplateConsr;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.cultivate.biz.CultivateRaysBiz;
import com.pcloud.book.cultivate.constant.CultivateRaysConstants;
import com.pcloud.book.cultivate.dao.CultivateRaysDao;
import com.pcloud.book.cultivate.dao.CultivateRaysRecordDao;
import com.pcloud.book.cultivate.dto.CultivateRaysConversionDTO;
import com.pcloud.book.cultivate.dto.CultivateRaysDTO;
import com.pcloud.book.cultivate.dto.CultivateRaysDelayDTO;
import com.pcloud.book.cultivate.entity.CultivateRays;
import com.pcloud.book.cultivate.entity.CultivateRaysRecord;
import com.pcloud.book.mq.delay.DelayMessageSender;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.book.util.properties.BookProps;
import com.pcloud.common.core.dto.AppletTemplateMessageDto;
import com.pcloud.common.core.mq.DelayQueueDTO;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.readercenter.rmall.dto.RmallUserBookMoneyDTO;
import com.pcloud.readercenter.rmall.entity.RmallBookMoneyRecord;
import com.pcloud.readercenter.rmall.enums.MoneyReceiveTypeEnum;
import com.pcloud.readercenter.wechat.entity.WechatUser;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @ClassName com.pcloud.book.cultivate.biz.impl.CultivateRaysBizImpl
 * @Author zhuyajie
 * @Description 宠物小睿
 * @Date 2021/7/16 13:50
 * @Version 1.0
 **/
@Component
public class CultivateRaysBizImpl implements CultivateRaysBiz {

    @Autowired
    private CultivateRaysDao cultivateRaysDao;
    @Autowired
    private CultivateRaysRecordDao cultivateRaysRecordDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private DelayMessageSender delayMessageSender;
    @Autowired
    private TemplateConsr templateConsr;

    @Override
    public Long createCultivate(Long wechatUserId, Long officialAccountsId) {
        CultivateRays rays = cultivateRaysDao.getByWechatUserId(wechatUserId);
        if (rays != null) {
            throw new BookBizException(BookBizException.ERROR, "已有宠物！");
        }
        CultivateRays cultivateRays = new CultivateRays();
        cultivateRays.setOfficialAccountsId(officialAccountsId);
        cultivateRays.setWechatUserId(wechatUserId);
        cultivateRays.setState(CultivateRaysConstants.CultivateRaysState.HUNGRY.getCode());
        cultivateRaysDao.insert(cultivateRays);
        return cultivateRays.getId();
    }

    @Override
    public CultivateRaysDTO getCultivate(Long wechatUserId, Long officialAccountsId) {
        CultivateRaysDTO cultivateRaysDTO = new CultivateRaysDTO();
        cultivateRaysDTO.setWechatUserId(wechatUserId);

        CultivateRays rays = cultivateRaysDao.getByWechatUserId(wechatUserId);
        if (null == rays) {
            cultivateRaysDTO.setHasPet(false);
            return cultivateRaysDTO;
        }
        BeanUtils.copyProperties(rays, cultivateRaysDTO);
        cultivateRaysDTO.setHasPet(true);
        WechatUser wechatUser = readerConsr.getWechatUser(wechatUserId);
        cultivateRaysDTO.setHeadPic(null == wechatUser ? null : wechatUser.getWechatUserHeadurl());
        cultivateRaysDTO.setNickName(null == wechatUser ? null : wechatUser.getWechatUserNickname());
        CultivateRaysRecord lastRecord = cultivateRaysRecordDao.getLastRecord(rays.getId(), CultivateRaysConstants.ChangeTypeEnum.GAINS_CONVERSION.getCode());
        if (null != lastRecord) {
            cultivateRaysDTO.setLastConversionTime(DateUtils.formatDate(lastRecord.getCreateTime(), DateUtils.DATE_FORMAT_DATETIME));
            cultivateRaysDTO.setHours(CultivateRaysConstants.GainsConversionEnum.getHoursByType(lastRecord.getGainsType()));
        }
        return cultivateRaysDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rmallMoneyConversion(CultivateRaysConversionDTO cultivateRaysConversionDTO) {
        CultivateRays rays = cultivateRaysDao.getByWechatUserId(cultivateRaysConversionDTO.getWechatUserId());
        if (rays == null) {
            throw new BookBizException(BookBizException.ERROR, "还没有宠物！");
        }
        Integer gainsType = cultivateRaysConversionDTO.getGainsType();
        //兑换所需书币
        Integer cost = CultivateRaysConstants.GainsConversionEnum.getCostByType(gainsType);
        if (null == cost) {
            throw new BookBizException(BookBizException.ERROR, "兑换类型错误！");
        }
        RmallUserBookMoneyDTO bookMoneyCount = readerConsr.getBookMoneyCount(cultivateRaysConversionDTO.getWechatUserId());
        Integer moneyCount = (null == bookMoneyCount || null == bookMoneyCount.getBookMoneyTotalCount()) ? 0 : bookMoneyCount.getBookMoneyTotalCount();
        if (cost > moneyCount) {
            throw new BookBizException(BookBizException.ERROR, "书币数量不足！");
        }
        Integer gains1 = null;
        Integer gains2 = null;
        Integer gains3 = null;
        if (CultivateRaysConstants.GainsConversionEnum.GAINS1.getType().equals(gainsType)) {
            gains1 = rays.getGains1() + 1;
        } else if (CultivateRaysConstants.GainsConversionEnum.GAINS2.getType().equals(gainsType)) {
            gains2 = rays.getGains2() + 1;
        } else if (CultivateRaysConstants.GainsConversionEnum.GAINS3.getType().equals(gainsType)) {
            gains3 = rays.getGains3() + 1;
        }
        //收入减少
        CultivateRays cultivateRays = new CultivateRays();
        cultivateRays.setId(rays.getId());
        cultivateRays.setGains1(gains1);
        cultivateRays.setGains2(gains2);
        cultivateRays.setGains3(gains3);
        cultivateRaysDao.update(cultivateRays);
        //增加兑换记录
        CultivateRaysRecord cultivateRaysRecord = new CultivateRaysRecord();
        cultivateRaysRecord.setCultivateId(rays.getId());
        cultivateRaysRecord.setChangeType(CultivateRaysConstants.ChangeTypeEnum.RMALL_MONEY_CONVERSION.getCode());
        String remark = "你花费" + cost + "书币兑换了1个" + CultivateRaysConstants.GainsConversionEnum.getNameByType(gainsType);
        cultivateRaysRecord.setRemark(remark);
        cultivateRaysRecord.setGainsType(gainsType);
        cultivateRaysRecordDao.insert(cultivateRaysRecord);
        //消耗书币
        ThreadPoolUtils.RMALL_SIGN_IN.execute(() -> {
            RmallBookMoneyRecord rmallBookMoneyRecord = new RmallBookMoneyRecord();
            rmallBookMoneyRecord.setWechatUserId(cultivateRaysConversionDTO.getWechatUserId());
            rmallBookMoneyRecord.setRecordType(MoneyReceiveTypeEnum.FOOD_CONVERSION.key);
            rmallBookMoneyRecord.setBookMoneyCount(-cost);
            readerConsr.insertBookMoneyRecord(rmallBookMoneyRecord);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void gainsConversion(CultivateRaysConversionDTO cultivateRaysConversionDTO) {
        Long wechatUserId = cultivateRaysConversionDTO.getWechatUserId();
        CultivateRays rays = cultivateRaysDao.getByWechatUserId(wechatUserId);
        if (rays == null) {
            throw new BookBizException(BookBizException.ERROR, "还没有宠物！");
        }
        Integer gainsType = cultivateRaysConversionDTO.getGainsType();
        //兑换时间
        Integer hours = CultivateRaysConstants.GainsConversionEnum.getHoursByType(gainsType);
        if (null == hours) {
            throw new BookBizException(BookBizException.ERROR, "兑换类型错误！");
        }
        Integer gains1 = null;
        Integer gains2 = null;
        Integer gains3 = null;
        if (CultivateRaysConstants.GainsConversionEnum.GAINS1.getType().equals(gainsType)) {
            if (null == rays.getGains1() || rays.getGains1() == 0) {
                throw new BookBizException(BookBizException.ERROR, "食物不足！");
            }
            gains1 = rays.getGains1() - 1;
        } else if (CultivateRaysConstants.GainsConversionEnum.GAINS2.getType().equals(gainsType)) {
            if (null == rays.getGains2() || rays.getGains2() == 0) {
                throw new BookBizException(BookBizException.ERROR, "食物不足！");
            }
            gains2 = rays.getGains2() - 1;
        } else if (CultivateRaysConstants.GainsConversionEnum.GAINS3.getType().equals(gainsType)) {
            if (null == rays.getGains3() || rays.getGains3() == 0) {
                throw new BookBizException(BookBizException.ERROR, "食物不足！");
            }
            gains3 = rays.getGains3() - 1;
        }
        //当前到期时间
        Date currentEndTime = rays.getEndTime();
        Date now = new Date();
        Date endTime;
        //总剩余到期时长
        Integer times = hours * 60 * 60 * 1000;
        if (currentEndTime.after(now)) {
            //当前剩余到期时长
            Long remainTimes = currentEndTime.getTime() - now.getTime();
            times = times + remainTimes.intValue();
        }
        if (times > 24 * 60 * 60 * 1000) {
            throw new BookBizException(BookBizException.ERROR, "食物装不下了，晚点再喂吧！");
        }
        endTime = DateUtils.addSecond(now, times / 1000);
        //收入减少
        CultivateRays cultivateRays = new CultivateRays();
        cultivateRays.setId(rays.getId());
        cultivateRays.setGains1(gains1);
        cultivateRays.setGains2(gains2);
        cultivateRays.setGains3(gains3);
        cultivateRays.setState(CultivateRaysConstants.CultivateRaysState.EATING.getCode());
        cultivateRays.setEndTime(endTime);
        cultivateRaysDao.update(cultivateRays);
        //增加兑换记录
        CultivateRaysRecord cultivateRaysRecord = new CultivateRaysRecord();
        cultivateRaysRecord.setCultivateId(rays.getId());
        cultivateRaysRecord.setChangeType(CultivateRaysConstants.ChangeTypeEnum.GAINS_CONVERSION.getCode());
        String remark = "你投喂了小睿1个" + CultivateRaysConstants.GainsConversionEnum.getNameByType(gainsType) + "，够吃" + hours + "小时";
        cultivateRaysRecord.setRemark(remark);
        cultivateRaysRecord.setGainsType(gainsType);
        cultivateRaysRecord.setHours(hours);
        cultivateRaysRecordDao.insert(cultivateRaysRecord);
        //延时
        addDelayEnergyConsumption(rays.getId(), wechatUserId, times);
    }

    @Override
    public void dealHoursConsumption(DelayQueueDTO delayQueueDTO) {
        CultivateRaysDelayDTO cultivateRaysDelayDTO = (CultivateRaysDelayDTO) delayQueueDTO.getMsg();
        Long wechatUserId = Long.valueOf(delayQueueDTO.getKey());
        //如果计划结束时间大于当前时间，仍在进食中，状态不处理
        CultivateRays cultivateRaysRecord = cultivateRaysDao.getByWechatUserId(wechatUserId);
        //防止时间上的误差，判断时加2分钟
        if (cultivateRaysRecord.getEndTime().after(DateUtils.addMinute(new Date(), 2))) {
            return;
        }
        //修改饥饿状态
        CultivateRays cultivateRays = new CultivateRays();
        cultivateRays.setId(cultivateRaysDelayDTO.getCultivateId());
        cultivateRays.setState(CultivateRaysConstants.CultivateRaysState.HUNGRY.getCode());
        cultivateRaysDao.update(cultivateRays);
        //发送喂食通知
        sendAppletTemplateMsg(wechatUserId, BookProps.getMiniOfficialAccountsId());
    }

    private void sendAppletTemplateMsg(Long wechatUserId, Long accountSettingId) {
        AppletTemplateMessageDto appletTemplateMessage;
        appletTemplateMessage = new AppletTemplateMessageDto();
        appletTemplateMessage.setAccountSettingId(accountSettingId);
        appletTemplateMessage.setWechatUserId(wechatUserId);
        appletTemplateMessage.setTempalteTypeCode("recall_remind");
        appletTemplateMessage.setPage("pages/smallpet/index");
        Map<String, String> tempMap = new HashMap<>();
        String text1 = "主人~我快要饿晕了";
        String text2 = "快来，还可以抢救下！";
        if ("pro".equals(BookProps.getSystemEnv())) {
            tempMap.put("thing3", text1);
            tempMap.put("thing2", text2);
        } else {
            tempMap.put("thing4", text1);
            tempMap.put("thing3", text2);
        }
        appletTemplateMessage.setData(tempMap);
        templateConsr.sendAppletMessageQueue(appletTemplateMessage);
    }

    /**
     * 延时队列
     *
     * @author：zhuyajie
     * @date：2021/7/16 18:39 * @param null
     */
    private void addDelayEnergyConsumption(Long cultivateId, Long wechatUserId, Integer times) {
        CultivateRaysDelayDTO cultivateRaysDelayDTO = new CultivateRaysDelayDTO();
        cultivateRaysDelayDTO.setCultivateId(cultivateId);
        DelayQueueDTO delayQueueDTONew = DelayQueueDTO.builder().key(wechatUserId.toString()).type(CultivateRaysConstants.HOURS_CONSUMPTION_DELAY).msg(cultivateRaysDelayDTO).timeout(times).build();
        delayMessageSender.send(delayQueueDTONew);
    }
}
