package com.liquidnet.service.platform.service.impl.candy;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.adam.entity.AdamUserMember;
import com.liquidnet.service.candy.constant.CandyRedisConst;
import com.liquidnet.service.candy.dto.CandyCouponCodeDto;
import com.liquidnet.service.candy.dto.CandyCouponInfoDto;
import com.liquidnet.service.candy.dto.CandyCouponRuleDto;
import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto;
import com.liquidnet.service.candy.entity.CandyCoupon;
import com.liquidnet.service.candy.entity.CandyCouponCode;
import com.liquidnet.service.candy.entity.CandyMgtCoupon;
import com.liquidnet.service.candy.entity.CandyUserCoupon;
import com.liquidnet.service.candy.mapper.CandyCouponMapper;
import com.liquidnet.service.platform.service.impl.adam.PlatformAdamUserMemberService;
import com.liquidnet.service.platform.service.impl.adam.dm.DMRdmService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class PlatformCandyCouponService extends ServiceImpl<CandyCouponMapper, CandyCoupon> {
    @Autowired
    private PlatformCandyCouponRuleService platformCandyCouponRuleService;
    @Autowired
    private PlatformCandyCouponCodeService platformCandyCouponCodeService;
    @Autowired
    private PlatformCandyUserCouponService platformCandyUserCouponService;
    @Autowired
    private PlatformAdamUserMemberService platformAdamUserMemberService;
    @Autowired
    private DMRdmService dmRdmService;
    @Autowired
    private RedisUtil redisUtil;

    private void issueCouponProcessing(final CandyMgtCoupon mgtCoupon, final CandyCoupon coupon) {
        List<CandyCouponRuleDto> couponRuleDtoList = platformCandyCouponRuleService.listForCouponRuleDto(coupon.getCouponId());

        CandyCouponInfoDto couponInfoDto = new CandyCouponInfoDto();
        BeanUtils.copyProperties(coupon, couponInfoDto);
        couponInfoDto.setUseRules(couponRuleDtoList);

        String couponInfoDtoKey = CandyRedisConst.BASIC_COUPON_INFO.concat(couponInfoDto.getCouponId());
        redisUtil.set(couponInfoDtoKey, couponInfoDto);

        LocalDateTime now = LocalDateTime.now();
        Integer eventAmt = mgtCoupon.getEventAmt();
        switch (coupon.getBindType()) {// 领取方式[0-用户输入兑换｜1-发放至用户]
            case 0:
                List<CandyCouponCode> initCouponCodeList = new ArrayList<>();
                boolean batchFlag = eventAmt > 1000;
                for (int i = 0; i < eventAmt; i++) {
                    CandyCouponCode couponCode = new CandyCouponCode();
                    couponCode.setCcode(RandomStringUtils.randomAlphanumeric(16));
                    couponCode.setCouponId(coupon.getCouponId());
                    couponCode.setState(0);
                    couponCode.setCreatedAt(now);

                    initCouponCodeList.add(couponCode);

                    if (batchFlag && initCouponCodeList.size() >= 1000) {
                        if (platformCandyCouponCodeService.saveBatch(initCouponCodeList)) {
                            initCouponCodeList.forEach(r -> {
                                redisUtil.set(CandyRedisConst.BASIC_COUPON_CODE.concat(r.getCcode()), CandyCouponCodeDto.getNew().copy(r));
                            });

                            initCouponCodeList.clear();
                        } else {
                            throw new LiquidnetServiceException("-1", "券发放失败");
                        }
                    }
                }

                if (initCouponCodeList.size() > 0 && platformCandyCouponCodeService.saveBatch(initCouponCodeList)) {
                    initCouponCodeList.forEach(r -> {
                        redisUtil.set(CandyRedisConst.BASIC_COUPON_CODE.concat(r.getCcode()), CandyCouponCodeDto.getNew().copy(r));
                    });

                    initCouponCodeList.clear();
                } else {
                    throw new LiquidnetServiceException("-1", "券发放失败");
                }
                break;
            case 1:
                List<CandyUserCoupon> initUserCouponList = new ArrayList<>();
                switch (mgtCoupon.getEventType()) {// 发放类型[1-会员｜2-手机号|10-全体用户]
                    case 1:
                        LocalDateTime nowEndTime = now.withHour(23).withMinute(59).withSecond(59);
                        LambdaQueryWrapper<AdamUserMember> queryWrapper = Wrappers.lambdaQuery(AdamUserMember.class).eq(AdamUserMember::getState, 1)
                                .gt(AdamUserMember::getExpiryAt, nowEndTime);
                        int userMemberCount = platformAdamUserMemberService.count(queryWrapper), num = 0, pSize = 1000;
                        log.info("发放券任务:userMemberCount:{}", userMemberCount);

                        while (userMemberCount > 0) {
                            initUserCouponList.clear();
                            String lastLimitSql = "LIMIT " + (num * pSize) + "," + pSize;
                            queryWrapper.orderByAsc(AdamUserMember::getMid).last(lastLimitSql);
                            queryWrapper.select(AdamUserMember::getUid);
                            List<AdamUserMember> userMemberList = platformAdamUserMemberService.list(queryWrapper);
                            int userMemberListSize = CollectionUtils.isEmpty(userMemberList) ? -1 : userMemberList.size();
                            for (int i = 0; i < userMemberListSize; i++) {
                                AdamUserMember userMember = userMemberList.get(i);

                                CandyUserCoupon userCoupon = new CandyUserCoupon();
                                userCoupon.setUcouponId(IDGenerator.get32UUID());
                                userCoupon.setMcouponId(mgtCoupon.getMcouponId());
                                userCoupon.setUid(userMember.getUid());
                                userCoupon.setCouponId(coupon.getCouponId());
                                userCoupon.setState(1);
                                userCoupon.setBindAt(now);

                                initUserCouponList.add(userCoupon);
                            }

                            if (!initUserCouponList.isEmpty()) {
                                if (platformCandyUserCouponService.saveBatch(initUserCouponList)) {
                                    initUserCouponList.forEach(r -> {
                                        String uckey = CandyRedisConst.BASIC_USER_COUPON.concat(r.getUid());

                                        List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtil.get(uckey);

                                        if (CollectionUtils.isEmpty(vos)) {
                                            vos = new ArrayList<>();
                                        }
                                        vos.add(CandyUserCouponBasicDto.getNew().copy(r, coupon, couponRuleDtoList));

                                        redisUtil.set(uckey, vos);
                                    });
                                } else {
                                    throw new LiquidnetServiceException("-1", "券发放失败");
                                }
                            }

                            num++;
                            userMemberCount -= pSize;
                            log.info("发放券任务:userMemberCount:{}," + lastLimitSql, userMemberCount);
                        }
                        break;
                    case 2:
                        String eventLimit = mgtCoupon.getEventLimit();
                        String[] eventLimitArr = eventLimit.split(",");

                        log.info("发放券任务:eventLimitArrLength:{}", eventLimitArr.length);
                        for (int i = 0; i < eventAmt; i++) {
                            for (String r : eventLimitArr) {
                                String uid = dmRdmService.getUidByMobile(r);

                                if (StringUtils.isNotEmpty(uid)) {
                                    CandyUserCoupon userCoupon = new CandyUserCoupon();
                                    userCoupon.setUcouponId(IDGenerator.get32UUID());
                                    userCoupon.setMcouponId(mgtCoupon.getMcouponId());
                                    userCoupon.setUid(uid);
                                    userCoupon.setCouponId(coupon.getCouponId());
                                    userCoupon.setState(1);
                                    userCoupon.setBindAt(now);

                                    initUserCouponList.add(userCoupon);
                                }
                            }
                        }

                        if (!initUserCouponList.isEmpty() && platformCandyUserCouponService.saveBatch(initUserCouponList)) {
                            initUserCouponList.forEach(r -> {
                                String uckey = CandyRedisConst.BASIC_USER_COUPON.concat(r.getUid());

                                List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtil.get(uckey);

                                if (CollectionUtils.isEmpty(vos)) {
                                    vos = new ArrayList<>();
                                }
                                vos.add(CandyUserCouponBasicDto.getNew().copy(r, coupon, couponRuleDtoList));

                                redisUtil.set(uckey, vos);
                            });
                        }
                        break;
                    case 10:// TODO: 2021/8/24 具体发放方式待定
                        break;
                    default:
                        log.warn("发放券任务:无法处理，无效的发放类型[mcouponId:{},eventType:{}]", mgtCoupon.getMcouponId(), mgtCoupon.getEventType());
                        break;
                }
                break;
            default:
                log.warn("发放券任务:无法处理，无效的领取方式[mcouponId:{},bindType:{}]", mgtCoupon.getMcouponId(), coupon.getBindType());
                break;
        }
    }

    /**
     * <p>
     * 发放代金券
     * </p>
     *
     * @param mgtCoupon CandyMgtCoupon
     * @param coupon    CandyCoupon
     */
    public void issueCashCouponHandler(final CandyMgtCoupon mgtCoupon, final CandyCoupon coupon) {
        this.issueCouponProcessing(mgtCoupon, coupon);
    }

    /**
     * <p>
     * 发放满减券
     * </p>
     *
     * @param mgtCoupon CandyMgtCoupon
     * @param coupon    CandyCoupon
     */
    public void issueOverMinusCouponHandler(CandyMgtCoupon mgtCoupon, CandyCoupon coupon) {
        this.issueCouponProcessing(mgtCoupon, coupon);
    }

    /**
     * <p>
     * 发放兑换券
     * </p>
     *
     * @param mgtCoupon CandyMgtCoupon
     * @param coupon    CandyCoupon
     */
    public void issueExchangeCouponHandler(final CandyMgtCoupon mgtCoupon, final CandyCoupon coupon) {
        this.issueCouponProcessing(mgtCoupon, coupon);
    }

    /**
     * <p>
     * 发放折扣券
     * </p>
     *
     * @param mgtCoupon CandyMgtCoupon
     * @param coupon    CandyCoupon
     */
    public void issueDiscountCouponHandler(final CandyMgtCoupon mgtCoupon, final CandyCoupon coupon) {
        this.issueCouponProcessing(mgtCoupon, coupon);
    }
}
