package com.kym.service.impl;

import cn.dev33.satoken.stp.StpUtil;


import com.github.pagehelper.PageHelper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.Coupon;
import com.kym.entity.queryParams.CouponQueryParam;
import com.kym.entity.common.PageBean;
import com.kym.entity.common.RedisKeys;
import com.kym.entity.User;
import com.kym.entity.UserCoupon;
import com.kym.entity.vo.UserCouponVo;
import com.kym.mapper.UserCouponMapper;
import com.kym.service.ActivityService;
import com.kym.service.CouponService;
import com.kym.service.UserCouponService;
import com.kym.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 用户优惠券关联表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2024-04-29
 */
@Service
public class UserCouponServiceImpl extends MPJBaseServiceImpl<UserCouponMapper, UserCoupon> implements UserCouponService {

    private final RedisTemplate<String, String> redisTemplate;

    private final ActivityService activityService;

    private final UserService userService;

    private final CouponService couponService;


    public UserCouponServiceImpl(RedisTemplate<String, String> redisTemplate, ActivityService activityService,
                                 UserService userService, CouponService couponService) {
        this.redisTemplate = redisTemplate;
        this.activityService = activityService;
        this.userService = userService;
        this.couponService = couponService;
    }

    @Override
    public PageBean<UserCouponVo> listUserCoupons(CouponQueryParam params) {
        var users = userService.lambdaQuery()
                .like(CommUtil.isNotEmptyAndNull(params.getMobilePhone()), User::getMobilePhone, params.getMobilePhone())
                .list();
        var userId2Mobile = users.stream().collect(Collectors.toMap(User::getId, User::getMobilePhone));
        var userIds = users.stream().map(User::getId).toList();

        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var list = lambdaQuery()
                .in(CommUtil.isNotEmptyAndNull(userIds), UserCoupon::getUserId, userIds)
                .eq(CommUtil.isNotEmptyAndNull(params.getActivityId()), UserCoupon::getId, params.getCouponId())
                .like(CommUtil.isNotEmptyAndNull(params.getActivityName()), UserCoupon::getActivityName, params.getActivityName())
                .eq(CommUtil.isNotEmptyAndNull(params.getCouponId()), UserCoupon::getId, params.getCouponId())
                .like(CommUtil.isNotEmptyAndNull(params.getCouponName()), UserCoupon::getCouponName, params.getCouponName())
                .eq(CommUtil.isNotEmptyAndNull(params.getCouponType()), UserCoupon::getCouponType, params.getCouponType())
                .eq(CommUtil.isNotEmptyAndNull(params.getUsageStatus()), UserCoupon::getUsageStatus, params.getUsageStatus())
                .orderByDesc(UserCoupon::getId)
                .list();

        var voList = list.stream().map(userCoupon -> {
            var vo = new UserCouponVo();
            BeanUtils.copyProperties(userCoupon, vo);
            vo.setMobilePhone(userId2Mobile.get(userCoupon.getUserId()));
            return vo;
        }).toList();
        var res = new PageBean<>(voList);
        return new PageBean<>(voList).setList(res);
    }

    @Override
    public void collectCoupon(Long couponId) {
        // 优惠券状态校验
        var coupon = couponService.lambdaQuery()
                .eq(Coupon::getId, couponId)
                .in(Coupon::getStatus, Coupon.STATUS_未开始, Coupon.STATUS_进行中)
                .one();

        if (coupon == null) {
            throw new BusinessException("优惠券不存在或已失效！");
        }

        if (coupon.getClaimedQuantity() >= coupon.getQuantity() && coupon.getQuantity() > 0) {
            throw new BusinessException("优惠券已领完！");
        }

        // 重复领取校验
        var userId = StpUtil.getLoginIdAsLong();
        var exist = redisTemplate.opsForSet().isMember(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);
        if (Boolean.TRUE.equals(exist)) {
            throw new BusinessException("优惠券已领取，请勿重复领取！");
        }

        // 活动
        var activity = activityService.getById(coupon.getActivityId());

        // 更新优惠券已领取数量
        coupon.setClaimedQuantity(coupon.getClaimedQuantity() + 1);

        // 校验优惠券数量是否已领完
        if (coupon.getClaimedQuantity() >= coupon.getQuantity() && coupon.getQuantity() > 0) {
            coupon.setStatus(Coupon.STATUS_已结束);
        }
        couponService.updateById(coupon);


        // 存入缓存和数据库
        redisTemplate.opsForSet().add(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);

        var userCoupon = new UserCoupon();
        userCoupon.setActivityId(coupon.getActivityId());
        userCoupon.setActivityName(activity.getName());
        userCoupon.setCouponId(coupon.getId());
        userCoupon.setCouponName(coupon.getName());
        userCoupon.setUserId(userId);
        userCoupon.setStartTime(LocalDateTime.now());
        userCoupon.setEndTime(LocalDateTime.now().with(LocalTime.MAX).plusDays(coupon.getValidity() - 1));
        userCoupon.setValidity(coupon.getValidity());
        userCoupon.setCouponType(coupon.getCouponType());
        userCoupon.setDiscount(coupon.getDiscount());
        userCoupon.setMinServiceMoney(coupon.getMinServiceMoney());
        userCoupon.setAllowStacke(coupon.getAllowStacke());
        userCoupon.setStatus(UserCoupon.STATUS_有效);
        userCoupon.setRemark(coupon.getRemark());
//        userCouponSender.sendMessage(userCoupon);
        save(userCoupon);


        // todo 优惠券活动终止时处理redis数据，优惠券失效或者使用之后该做什么操作？
    }

    @Override
    public List<UserCoupon> listStationAvailableCoupons(Map<String, ?> params) {
        return baseMapper.listStationAvailableCoupons(params);
    }

}
