package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.modules.member.service.MemberService;
import cn.lili.modules.promotion.entity.dos.Coupon;
import cn.lili.modules.promotion.entity.dos.CouponActivity;
import cn.lili.modules.promotion.entity.dos.CouponActivityItem;
import cn.lili.modules.promotion.entity.dos.MemberCoupon;
import cn.lili.modules.promotion.entity.dto.CouponActivityDTO;
import cn.lili.modules.promotion.entity.dto.CouponActivityTrigger;
import cn.lili.modules.promotion.entity.enums.*;
import cn.lili.modules.promotion.entity.vos.CouponActivityItemVO;
import cn.lili.modules.promotion.entity.vos.CouponActivityVO;
import cn.lili.modules.promotion.mapper.CouponActivityMapper;
import cn.lili.modules.promotion.service.*;
import cn.lili.modules.promotion.tools.PromotionTools;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import groovy.util.logging.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 优惠券活动业务层实现
 *
 * @author Bulbasaur
 * @since 2021/5/20 6:10 下午
 */
@Slf4j
@Service
public class CouponActivityServiceImpl extends AbstractPromotionsServiceImpl<CouponActivityMapper, CouponActivity> implements CouponActivityService {

    @Autowired
    private CouponService couponService;
    @Autowired
    private MemberCouponService memberCouponService;
    @Autowired
    private CouponActivityItemService couponActivityItemService;


    @Autowired
    private MemberCouponSignService memberCouponSignService;

    @Autowired
    private MemberService memberService;


    @Autowired
    private Cache<List<CouponActivityVO>> cache;

    @Override
    public CouponActivityVO getCouponActivityVO(String couponActivityId) {
        CouponActivity couponActivity = this.getById(couponActivityId);
        return new CouponActivityVO(couponActivity, couponActivityItemService.getCouponActivityItemListVO(couponActivityId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void specify(CouponActivity couponActivity) {
        //获取活动优惠券发送范围
        List<Map<String, Object>> member = this.getMemberList(couponActivity);

        //如果指定会员发券，则当下直接进行发送，如果是全体会员发券，则变更为用户登录首页进行请求发券
        //PS:即不主动发券，需要用户在活动时间内登录自动领取优惠券，类似美团、饿了么 的发放方式
        if (couponActivity.getActivityScope().equals(CouponActivitySendTypeEnum.DESIGNATED.name())) {
            //会员拆成多个小组进行发送
            List<List<Map<String, Object>>> memberGroup = new ArrayList<>();

            //循环分组
            for (int i = 0; i < (member.size() / 100 + (member.size() % 100 == 0 ? 0 : 1)); i++) {
                int endPoint = Math.min((100 + (i * 100)), member.size());
                memberGroup.add(member.subList((i * 100), endPoint));
            }

            //优惠优惠券活动的优惠券列表
            List<CouponActivityItem> couponActivityItems = couponActivityItemService.getCouponActivityList(couponActivity.getId());
            //发送优惠券
            for (List<Map<String, Object>> memberList : memberGroup) {
                sendCoupon(memberList, couponActivityItems);
            }
        }

    }

    /**
     * 初始化促销字段
     *
     * @param promotions 促销实体
     */
    @Override
    public void initPromotion(CouponActivity promotions) {
        super.initPromotion(promotions);
        if (promotions instanceof CouponActivityDTO) {
            CouponActivityDTO couponActivityDTO = (CouponActivityDTO) promotions;
            //如果有会员，则写入会员信息
            if (couponActivityDTO.getMemberDTOS() != null && !couponActivityDTO.getMemberDTOS().isEmpty()) {
                couponActivityDTO.setActivityScopeInfo(JSONUtil.toJsonStr(couponActivityDTO.getMemberDTOS()));
            }
        }
    }

    /**
     * 检查优惠券活动参数
     *
     * @param couponActivity 优惠券活动实体
     */
    @Override
    public void checkPromotions(CouponActivity couponActivity) {
        super.checkPromotions(couponActivity);

        if (couponActivity instanceof CouponActivityDTO) {
            CouponActivityDTO couponActivityDTO = (CouponActivityDTO) couponActivity;
            //指定会员判定
            if (couponActivity.getActivityScope().equals(CouponActivitySendTypeEnum.DESIGNATED.name()) && couponActivityDTO.getMemberDTOS().isEmpty()) {
                throw new ServiceException(ResultCode.COUPON_ACTIVITY_MEMBER_ERROR);
            }
            // 检查优惠券
            this.checkCouponActivityItem(couponActivityDTO.getCouponActivityItems());
        }

    }

    /**
     * 更新优惠券活动商品信息
     *
     * @param couponActivity 优惠券活动实体
     * @return 是否更新成功
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean updatePromotionsGoods(CouponActivity couponActivity) {
        boolean result = super.updatePromotionsGoods(couponActivity);
        if (couponActivity instanceof CouponActivityDTO && !PromotionsStatusEnum.CLOSE.name().equals(couponActivity.getPromotionStatus()) && PromotionsScopeTypeEnum.PORTION_GOODS.name().equals(couponActivity.getScopeType())) {
            CouponActivityDTO couponActivityDTO = (CouponActivityDTO) couponActivity;
            //创建优惠券活动子列表
            for (CouponActivityItem couponActivityItem : couponActivityDTO.getCouponActivityItems()) {
                couponActivityItem.setActivityId(couponActivityDTO.getId());
            }
            // 更新优惠券活动项信息
            result = couponActivityItemService.saveBatch(couponActivityDTO.getCouponActivityItems());
        }
        return result;
    }

    /**
     * 更新优惠券活动信息到商品索引
     *
     * @param couponActivity 促销实体
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEsGoodsIndex(CouponActivity couponActivity) {


        switch (CouponActivityTypeEnum.valueOf(couponActivity.getCouponActivityType())) {

            // 精准发券 则立即发放
            case SPECIFY:
                this.specify(couponActivity);
                break;
            //其他活动则是缓存模块，根据缓存中的优惠券活动信息来确认发放优惠券测略
            case INVITE_NEW:
            case AUTO_COUPON:
            case REGISTERED:
                this.resetCache(couponActivity.getCouponActivityType());
                break;
        }

    }

    @Override
    public List<MemberCoupon> trigger(CouponActivityTrigger couponActivityTrigger) {
        //获取当前正在进行的优惠券活动
        List<CouponActivityVO> couponActivities = currentCouponActivity(couponActivityTrigger.getCouponActivityTypeEnum().name());


        /**
         * 自动发送优惠券则需要补足日志
         */
        if (couponActivityTrigger.getCouponActivityTypeEnum().equals(CouponActivityTypeEnum.AUTO_COUPON)) {
            couponActivities = memberCouponSignService.receiveCoupon(couponActivities);
        }

        //优惠券发放列表
        List<CouponActivityItemVO> couponActivityItemVOS = new ArrayList<>();

        //准备发放优惠券活动的列表
        couponActivities.stream().forEach(item -> couponActivityItemVOS.addAll(item.getCouponActivityItems()));

        AuthUser authUser = new AuthUser();
        authUser.setId(couponActivityTrigger.getUserId());
        authUser.setNickName(couponActivityTrigger.getNickName());


        return this.sendCoupon(authUser, couponActivityItemVOS);
    }


    /**
     * 当前促销类型
     *
     * @return 当前促销类型
     */
    @Override
    public PromotionTypeEnum getPromotionType() {
        return PromotionTypeEnum.COUPON_ACTIVITY;
    }

    /**
     * 缓存key生成策略
     *
     * @param couponActivityType 优惠券活动类型
     * @return 缓存key
     */
    private String cacheKey(String couponActivityType) {
        return CachePrefix.CURRENT_COUPON_ACTIVITY.getPrefix() + couponActivityType;
    }

    /**
     * 当前进行的活动
     *
     * @return 当前进行的活动列表
     */
    private List<CouponActivityVO> currentCouponActivity() {
        return currentCouponActivity(CouponActivityTypeEnum.AUTO_COUPON.name());
    }

    /**
     * 当前进行的活动
     *
     * @return 当前进行的活动列表
     */
    private List<CouponActivityVO> currentCouponActivity(String couponActivityTypeEnum) {
        //获取缓存中的活动
        List<CouponActivityVO> couponActivityList = cache.get(cacheKey(couponActivityTypeEnum));
        if (couponActivityList == null) {
            return ongoingActivities(resetCache(couponActivityTypeEnum));
        }
        return ongoingActivities(couponActivityList);
    }

    /**
     * 从生效的活动优惠券中，过滤出正在进行的活动列表
     *
     * @param activityVOS
     * @return
     */
    private List<CouponActivityVO> ongoingActivities(List<CouponActivityVO> activityVOS) {
        if (activityVOS == null || activityVOS.size() == 0) {
            return new ArrayList<>();
        }
        return activityVOS.stream().filter(item -> {
            return item.getPromotionStatus().equals(PromotionsStatusEnum.START.name());
        }).collect(Collectors.toList());
    }

    /**
     * 重写缓存中的活动优惠券信息
     */
    private List<CouponActivityVO> resetCache(String couponActivityType) {

        LambdaQueryWrapper<CouponActivity> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        //如果结束时间大于当前时间，则表示有效
        lambdaQueryWrapper.gt(CouponActivity::getEndTime, new Date());
        //发送策略
        lambdaQueryWrapper.eq(CouponActivity::getActivityScope, CouponActivitySendTypeEnum.ALL);
        //活动类型
        lambdaQueryWrapper.eq(CouponActivity::getCouponActivityType, couponActivityType);

        //查询出结果，缓存后返回
        List<CouponActivity> couponActivities = list(lambdaQueryWrapper);

        List<CouponActivityVO> couponActivityVOS = new ArrayList<>();
        for (CouponActivity couponActivity : couponActivities) {
            couponActivityVOS.add(new CouponActivityVO(couponActivity, couponActivityItemService.getCouponActivityItemListVO(couponActivity.getId())));
        }

        cache.put(cacheKey(couponActivityType), couponActivityVOS);
        return couponActivityVOS;
    }

    /**
     * 定向发送优惠券
     *
     * @param memberList          用户列表
     * @param couponActivityItems 优惠券列表
     */
    private void sendCoupon(List<Map<String, Object>> memberList, List<CouponActivityItem> couponActivityItems) {

        for (Map<String, Object> map : memberList) {
            AuthUser authUser = new AuthUser();
            authUser.setId(map.get("id").toString());
            authUser.setNickName(map.get("nick_name").toString());

            sendCoupon(authUser, couponActivityItems);

        }
    }

    /**
     * 给当前用户发送优惠券
     * 1.循环优惠券列表
     * 2.判断优惠券每个会员发送数量
     * 3.记录优惠券发送数量
     *
     * @param authUser            发送目标用户
     * @param couponActivityItems 优惠券列表
     */
    private List<MemberCoupon> sendCoupon(AuthUser authUser, List<? extends CouponActivityItem> couponActivityItems) {

        //最终优惠券列表
        List<MemberCoupon> finalCoupons = new ArrayList<>();

        //循环优惠券赠送列表
        for (CouponActivityItem couponActivityItem : couponActivityItems) {
            //获取优惠券
            Coupon coupon = couponService.getById(couponActivityItem.getCouponId());
            //判断优惠券是否存在
            if (coupon != null) {
                //循环优惠券的领取数量
                int activitySendNum = couponActivityItem.getNum();

                List<MemberCoupon> memberCouponList = new ArrayList<>();
                for (int i = 1; i <= activitySendNum; i++) {
                    MemberCoupon memberCoupon = new MemberCoupon(coupon);
                    memberCoupon.setMemberId(authUser.getId());
                    memberCoupon.setMemberName(authUser.getNickName());
                    memberCoupon.setMemberCouponStatus(MemberCouponStatusEnum.NEW.name());
                    memberCoupon.setPlatformFlag(PromotionTools.PLATFORM_ID.equals(coupon.getStoreId()));
                    memberCouponList.add(memberCoupon);
                }

                finalCoupons.addAll(memberCouponList);
                //批量添加优惠券
                memberCouponService.saveBatch(memberCouponList);
                //添加优惠券已领取数量
                couponService.receiveCoupon(couponActivityItem.getCouponId(), memberCouponList.size());
            } else {
                log.error("赠送优惠券失败,当前优惠券不存在:" + couponActivityItem.getCouponId());
            }
        }
        if (finalCoupons.isEmpty()) {
            return new ArrayList<>();
        }
        return finalCoupons;

    }

    /**
     * 获取优惠券的范围范围
     * 此方法用于精准发券
     *
     * @param couponActivity 优惠券活动
     * @return 获取优惠券的会员列表
     */
    private List<Map<String, Object>> getMemberList(CouponActivity couponActivity) {
        //判断优惠券的发送范围，获取会员列表

        List<String> ids = new ArrayList<>();
        if (JSONUtil.isJsonArray(couponActivity.getActivityScopeInfo())) {
            JSONArray array = JSONUtil.parseArray(couponActivity.getActivityScopeInfo());
            ids = array.toList(Map.class).stream().map(i -> i.get("id").toString()).collect(Collectors.toList());
        }
        return memberService.listFieldsByMemberIds("id,nick_name", ids);
    }

    /**
     * 检查优惠券
     *
     * @param couponActivityItems 优惠券列表
     */
    private void checkCouponActivityItem(List<CouponActivityItem> couponActivityItems) {
        //优惠券数量判定
        if (couponActivityItems.isEmpty()) {
            throw new ServiceException(ResultCode.COUPON_ACTIVITY_ITEM_ERROR);
        } else if (couponActivityItems.size() > 10) {
            throw new ServiceException(ResultCode.COUPON_ACTIVITY_ITEM_MUST_NUM_ERROR);
        } else {
            for (CouponActivityItem item : couponActivityItems) {
                if (item.getNum() == null || item.getNum() <= 0) {
                    throw new ServiceException(ResultCode.COUPON_ACTIVITY_ITEM_NUM_ERROR);
                }
                if (item.getNum() > 2) {
                    throw new ServiceException(ResultCode.COUPON_ACTIVITY_ITEM_NUM_MAX_VALUE_2);
                }
            }
        }
    }
}
