package com.liquidnet.service.platform.controller.candy.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.candy.constant.CandyRedisConst;
import com.liquidnet.service.candy.dto.CandyCommonCouponBasicDto;
import com.liquidnet.service.candy.entity.CandyCommonCoupon;
import com.liquidnet.service.candy.entity.CandyCoupon;
import com.liquidnet.service.platform.service.impl.candy.PlatformCandyCommonCouponService;
import com.liquidnet.service.platform.service.impl.candy.PlatformCandyCouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 券到期检查任务
 * </p>
 * - 兑换类
 * --- 检查[coupon.redeem_stop]
 * - 发放类
 * --- 公有券：检查[coupon.expire_at]
 * --- 私有券：检查[user_coupon.dued_at]
 *
 * @author zhanggb
 * Created by IntelliJ IDEA at 2021/9/1
 */
@Slf4j
@RestController
@RequestMapping("ccoupon/task/due")
public class CandyCouponDueTaskController {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private PlatformCandyCouponService platformCandyCouponService;
    @Autowired
    private PlatformCandyCommonCouponService platformCandyCommonCouponService;

    /**
     * <p>
     * 兑换类
     * </p>
     * - 更新兑换码状态
     * - 同步REDIS.DTO
     *
     * @return ResponseDto<String>
     */
    @PutMapping("redeem")
    public ResponseDto<String> processForRedeem() {
        LocalDateTime now = LocalDateTime.now();



        return ResponseDto.success();
    }

    /**
     * <p>
     * 发放类-公有券
     * </p>
     * - 更新公有券状态
     * - 同步REDIS.DTO
     *
     * @return ResponseDto<String>
     */
    @PutMapping("common")
    public ResponseDto<String> processForCommon() {
        LocalDateTime now = LocalDateTime.now();

        // 查取状态可用的公有券
        LambdaQueryWrapper<CandyCommonCoupon> commonCouponQueryWrapper = Wrappers.lambdaQuery(CandyCommonCoupon.class);
        commonCouponQueryWrapper.eq(CandyCommonCoupon::getState, 1);
        commonCouponQueryWrapper.select(CandyCommonCoupon::getMid, CandyCommonCoupon::getCcouponId, CandyCommonCoupon::getCouponId);
        List<CandyCommonCoupon> commonCouponList = platformCandyCommonCouponService.list(commonCouponQueryWrapper);
        log.info("券到期检查:公有券[可用券总数:{}] >>> BEGIN BEGIN BEGIN", commonCouponList.size());

        if (!CollectionUtils.isEmpty(commonCouponList)) {
            List<CandyCommonCoupon> updateCommonCouponList = new ArrayList<>();

            // 查取状态可用的公有券 - 券ID集
            Object[] commonCouponIdArr = commonCouponList.stream().map(CandyCommonCoupon::getCouponId).toArray();
            Map<String, List<CandyCommonCoupon>> commonCouponIdToListMap = commonCouponList.stream().collect(Collectors.groupingBy(CandyCommonCoupon::getCouponId));

            // 查取状态可用的公有券 - 对应的过期券列表
            LambdaQueryWrapper<CandyCoupon> couponQueryWrapper = Wrappers.lambdaQuery(CandyCoupon.class);
            couponQueryWrapper.in(CandyCoupon::getCouponId, commonCouponIdArr);
            couponQueryWrapper.le(CandyCoupon::getExpireAt, now);
            int totalCount = platformCandyCouponService.count(couponQueryWrapper), remainCount = totalCount, num = 0, pSize = 1000;
            log.info("券到期检查:公有券[可用券总数:{},其中到期券ID数:{}]", commonCouponList.size(), totalCount);

            couponQueryWrapper.orderByAsc(CandyCoupon::getMid);
            while (remainCount > 0) {
                String lastLimitSql = "LIMIT " + (num * pSize) + "," + pSize;
                couponQueryWrapper.last(lastLimitSql);
                couponQueryWrapper.select(CandyCoupon::getMid, CandyCoupon::getCouponId);
                List<CandyCoupon> couponList = platformCandyCouponService.list(couponQueryWrapper);

                int couponListSize = CollectionUtils.isEmpty(couponList) ? -1 : couponList.size();
                for (int i = 0; i < couponListSize; i++) {
                    CandyCoupon coupon = couponList.get(i);

                    List<CandyCommonCoupon> inCommonCouponList = commonCouponIdToListMap.get(coupon.getCouponId());
                    inCommonCouponList.forEach(r -> {
                        r.setState(3);
                        r.setOperator("system");
                        r.setUpdatedAt(now);

                        updateCommonCouponList.add(r);
                    });
                }

                num++;
                remainCount -= pSize;
            }

            if (!CollectionUtils.isEmpty(updateCommonCouponList)) {
                if (platformCandyCommonCouponService.updateBatchById(updateCommonCouponList, updateCommonCouponList.size())) {
                    String ccKey = CandyRedisConst.BASIC_COMMON_COUPON;
                    List<CandyCommonCouponBasicDto> vos = (List<CandyCommonCouponBasicDto>) redisUtil.get(ccKey);

                    if (!CollectionUtils.isEmpty(vos)) {
                        Map<String, CandyCommonCouponBasicDto> vosMap = vos.stream().collect(Collectors.toMap(CandyCommonCouponBasicDto::getCcouponId, t -> t));
                        updateCommonCouponList.forEach(r -> {
                            vos.removeIf(v -> v.getCcouponId().equals(r.getCcouponId()));

                            CandyCommonCouponBasicDto commonCouponBasicDto = vosMap.get(r.getCcouponId());
                            commonCouponBasicDto.setState(3);
                            vos.add(commonCouponBasicDto);
                        });

                        redisUtil.set(ccKey, vos);
                    }
                } else {
                    throw new LiquidnetServiceException("-1", String.format("券到期处理失败[updateCommonCouponList.size=%s]", updateCommonCouponList.size()));
                }
            }
            log.info("券到期检查:公有券[可用券总数:{},到期券ID数:{},到期券处理数:{}] >>> END END END", commonCouponList.size(), totalCount, updateCommonCouponList.size());
        }
        return ResponseDto.success();
    }

    /**
     * <p>
     * 发放类-私有券
     * </p>
     * - 更新用户券状态
     * - 同步REDIS.DTO
     *
     * @return ResponseDto<String>
     */
    @PutMapping("user")
    public ResponseDto<String> processForUser() {
        LocalDateTime now = LocalDateTime.now();
        return ResponseDto.success();
    }
}
