package com.slodon.b2b2c.job;

import com.slodon.b2b2c.core.constant.MemberTplConst;
import com.slodon.b2b2c.core.util.AssertUtil;
import com.slodon.b2b2c.core.util.TimeUtil;
import com.slodon.b2b2c.model.promotion.*;
import com.slodon.b2b2c.promotion.pojo.CouponMember;
import com.slodon.b2b2c.promotion.pojo.SeckillStageProduct;
import com.slodon.b2b2c.promotion.pojo.SeckillStageProductBindMember;
import com.slodon.b2b2c.starter.mq.entity.MessageSendProperty;
import com.slodon.b2b2c.starter.mq.entity.MessageSendVO;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static com.slodon.b2b2c.core.constant.StarterConfigConst.MQ_EXCHANGE_NAME;
import static com.slodon.b2b2c.core.constant.StarterConfigConst.MQ_QUEUE_NAME_MEMBER_MSG;

@Slf4j
@Component
@Configuration      //1.主要用于标记配置类，兼备Component的效果。
//@EnableScheduling   //2.开启定时任务
public class PromotionJob {

    @Resource
    private PresellModel presellModel;
    @Resource
    private PresellOrderExtendModel presellOrderExtendModel;
    @Resource
    private CouponMemberModel couponMemberModel;
    @Resource
    private SeckillStageProductModel seckillStageProductModel;
    @Resource
    private LadderGroupModel ladderGroupModel;
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 系统自动发起定金预售赔偿处理(商家未在约定时间内发货，商家需退还定金并赔偿买家定金金额的2倍)
     * 每隔一小时执行一次
     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
//    @SchedulerLock(name = "jobPreSellDepositCompensate", lockAtMostFor = "3600000", lockAtLeastFor = "3000000")
    public void jobPreSellDepositCompensate() {
        log.info("jobPreSellDepositCompensate() start");
        try {
            boolean jobResult = presellModel.jobPreSellDepositCompensate();
            AssertUtil.isTrue(!jobResult, "[jobPreSellDepositCompensate] 定时任务自动发起定金预售赔偿时失败");
        } catch (Exception e) {
            log.error("jobPreSellDepositCompensate()", e);
        }
        log.info("jobPreSellDepositCompensate() end");
    }

    /**
     * 系统定时检查即将过期优惠券，并对会员发送消息提醒
     * 每天早上六点半执行
     */
//    @Scheduled(cron = "0 30 6 * * ?")
//    @SchedulerLock(name = "jobSystemCheckExpiredCouponRemind", lockAtMostFor = "86400000", lockAtLeastFor = "82800000")
    public void jobSystemCheckExpiredCouponRemind() {
        log.info("jobSystemCheckExpiredCouponRemind() start");
        try {
            List<CouponMember> couponMemberList = couponMemberModel.jobSystemCheckExpiredCoupon();
            if (!CollectionUtils.isEmpty(couponMemberList)) {
                for (CouponMember couponMember : couponMemberList) {
                    String expiredDate = TimeUtil.getDateTimeString(couponMember.getEffectiveEnd());
                    //构造消息通知对象
                    //微信消息通知
                    List<MessageSendProperty> messageSendPropertyList = new ArrayList<>();
                    messageSendPropertyList.add(new MessageSendProperty("first", "您有一张优惠券即将过期，请登录查看"));
                    messageSendPropertyList.add(new MessageSendProperty("keyword1", expiredDate));
                    String msgLinkInfo = "{\"type\":\"coupon_news\"}";
                    String[] templateParam = {expiredDate};
                    MessageSendVO messageSendVO = new MessageSendVO(messageSendPropertyList, couponMember.getMemberId(),
                            MemberTplConst.COUPON_EXPIRED_REMINDER, msgLinkInfo, templateParam);

                    //发送到mq
                    rabbitTemplate.convertAndSend(MQ_EXCHANGE_NAME, MQ_QUEUE_NAME_MEMBER_MSG, messageSendVO);
                }
            }
        } catch (Exception e) {
            log.error("jobSystemCheckExpiredCouponRemind()", e);
        }
        log.info("jobSystemCheckExpiredCouponRemind() end");
    }

    /**
     * 秒杀场次开始前五秒将秒杀货品状态更新
     * 每小时的59:55执行一次
     */
//    @Scheduled(cron = "55 59 * * * ?")
//    @SchedulerLock(name = "jobSaveSeckillStageProduct", lockAtMostFor = "3600000", lockAtLeastFor = "3000000")
    public void jobSaveSeckillStageProduct() {
        log.info("jobSaveSeckillStageProduct() start");
        try {
            boolean jobResult = seckillStageProductModel.jobSaveSeckillStageProduct();
            AssertUtil.isTrue(!jobResult, "[jobSaveSeckillStageProduct] 定时保存秒杀场次活动货品状态失败");
        } catch (Exception e) {
            log.error("jobSaveSeckillStageProduct()", e);
        }
        log.info("jobSaveSeckillStageProduct() end");
    }

    /**
     * 秒杀结束后将redis中的货品库存放入货品表
     * 每分钟执行一次
     */
//    @Scheduled(cron = "0 0/1 * * * ? ")
//    @SchedulerLock(name = "jobRecoverSeckillProduct", lockAtMostFor = "60000", lockAtLeastFor = "50000")
    public void jobRecoverSeckillProduct() {
        log.info("jobRecoverSeckillProduct() start");
        try {
            boolean jobResult = seckillStageProductModel.jobRecoverSeckillProduct();
            AssertUtil.isTrue(!jobResult, "[jobRecoverSeckillProduct] 定时恢复redis中秒杀货品到数据库");
        } catch (Exception e) {
            log.error("jobRecoverSeckillProduct()", e);
        }
        log.info("jobRecoverSeckillProduct() end");
    }

    /**
     * 定时处理秒杀场次已开始并且未审核的商品
     * 每小时执行一次
     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
//    @SchedulerLock(name = "jobUpdateSeckillProduct", lockAtMostFor = "3600000", lockAtLeastFor = "3000000")
    public void jobUpdateSeckillProduct() {
        log.info("jobUpdateSeckillProduct() start");
        try {
            boolean jobResult = seckillStageProductModel.jobUpdateSeckillProduct();
            AssertUtil.isTrue(!jobResult, "[jobUpdateSeckillProduct] 定时处理秒杀场次已开始并且未审核的商品");
        } catch (Exception e) {
            log.error("jobUpdateSeckillProduct()", e);
        }
        log.info("jobUpdateSeckillProduct() end");
    }

    /**
     * 秒杀商品设置提醒成功后，距离秒杀场次开始时间3分钟时，向会员消息推送；
     */
//    @Scheduled(cron = "0 57 * * * ?")
//    @SchedulerLock(name = "jobSendSeckillStageProductNotice", lockAtMostFor = "3600000", lockAtLeastFor = "3000000")
    public void jobSendSeckillStageProductNotice() {
        log.info("jobSendSeckillStageProductNotice() start");
        try {
            List<SeckillStageProductBindMember> productBindMemberList = seckillStageProductModel.jobSendSeckillStageProductNotice();
            if (!CollectionUtils.isEmpty(productBindMemberList)) {
                productBindMemberList.forEach(seckillStageProductBindMember -> {
                    SeckillStageProduct seckillStageProduct = seckillStageProductModel.getSeckillStageProductByStageProductId(seckillStageProductBindMember.getStageProductId());
                    AssertUtil.notNull(seckillStageProduct, "秒杀商品信息为空");
                    //添加消息通知
                    //微信消息通知
                    List<MessageSendProperty> messageSendPropertyList = new ArrayList<>();
                    messageSendPropertyList.add(new MessageSendProperty("first", "您预约的秒杀活动即将开始。"));
                    messageSendPropertyList.add(new MessageSendProperty("keyword1", seckillStageProductBindMember.getMemberName()));
                    messageSendPropertyList.add(new MessageSendProperty("keyword2", "商品秒杀-" + seckillStageProduct.getGoodsName()));
                    messageSendPropertyList.add(new MessageSendProperty("keyword3", TimeUtil.getDateTimeString(seckillStageProduct.getStartTime())));
                    messageSendPropertyList.add(new MessageSendProperty("remark", "请及时参与。"));

                    String msgLinkInfo = "{\"type\":\"appointment_news\",\"productId\":\""
                            + seckillStageProduct.getProductId() + "\",\"goodsId\":\"" + seckillStageProduct.getGoodsId() + "\"}";
                    String[] templateParam = {seckillStageProduct.getGoodsName()};
                    MessageSendVO messageSendVO = new MessageSendVO(messageSendPropertyList, seckillStageProductBindMember.getMemberId(),
                            MemberTplConst.SCEKILL_START, msgLinkInfo, templateParam);
                    //发送到mq
                    rabbitTemplate.convertAndSend(MQ_EXCHANGE_NAME, MQ_QUEUE_NAME_MEMBER_MSG, messageSendVO);
                });
            }
        } catch (Exception e) {
            log.error("jobSendSeckillStageProductNotice()", e);
        }
        log.info("jobSendSeckillStageProductNotice() end");
    }

    /**
     * 定时修改阶梯团尾款信息
     * 每隔一分钟执行一次
     */
//    @Scheduled(cron = "0 0/1 * * * ?")
//    @SchedulerLock(name = "jobUpdateLadderGroup", lockAtMostFor = "60000", lockAtLeastFor = "50000")
    public void jobUpdateLadderGroup() {
        log.info("jobUpdateLadderGroup() start");
        try {
            boolean jobResult = ladderGroupModel.jobUpdateLadderGroup();
            AssertUtil.isTrue(!jobResult, "[jobUpdateLadderGroup] 定时修改阶梯团尾款信息时失败");
        } catch (Exception e) {
            log.error("jobUpdateLadderGroup()", e);
        }
        log.info("jobUpdateLadderGroup() end");
    }

    /**
     * 系统定时发送待支付尾款提醒
     * 每小时执行一次
     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
//    @SchedulerLock(name = "jobSystemSendBalancePaymentRemind", lockAtMostFor = "3600000", lockAtLeastFor = "3540000")
    public void jobSystemSendBalancePaymentRemind() {
        log.info("jobSystemSendBalancePaymentRemind() start");
        try {
            boolean jobResult = presellOrderExtendModel.jobSystemSendBalancePaymentRemind();
            AssertUtil.isTrue(!jobResult, "[jobSystemSendBalancePaymentRemind] 系统定时发送待支付尾款提醒");
        } catch (Exception e) {
            log.error("jobSystemSendBalancePaymentRemind()", e);
        }
        log.info("jobSystemSendBalancePaymentRemind() end");
    }

    /**
     * 系统定时发送预售商品待发货提醒
     * 每小时执行一次
     */
//    @Scheduled(cron = "0 0 0/1 * * ?")
//    @SchedulerLock(name = "jobSystemSendDeliverRemind", lockAtMostFor = "3600000", lockAtLeastFor = "3540000")
    public void jobSystemSendDeliverRemind() {
        log.info("jobSystemSendDeliverRemind() start");
        try {
            boolean jobResult = presellOrderExtendModel.jobSystemSendDeliverRemind();
            AssertUtil.isTrue(!jobResult, "[jobSystemSendDeliverRemind] 系统定时发送预售商品待发货提醒");
        } catch (Exception e) {
            log.error("jobSystemSendDeliverRemind()", e);
        }
        log.info("jobSystemSendDeliverRemind() end");
    }
}
