package com.kym.service.miniapp.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
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.admin.Coupon;
import com.kym.entity.admin.queryParams.CouponQueryParam;
import com.kym.entity.common.PageBean;
import com.kym.entity.common.RedisKeys;
import com.kym.entity.miniapp.OrderCoupon;
import com.kym.entity.miniapp.User;
import com.kym.entity.miniapp.UserCoupon;
import com.kym.entity.miniapp.vo.UserCouponVo;
import com.kym.entity.miniapp.vo.UserOrderCouponVo;
import com.kym.mapper.miniapp.UserCouponMapper;
import com.kym.service.admin.ActivityService;
import com.kym.service.admin.CouponService;
import com.kym.service.miniapp.UserCouponService;
import com.kym.service.miniapp.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.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户优惠券关联表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2024-04-29
 */
@Service
@DS("db-miniapp")
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) {
    // 分页设置
    PageHelper.startPage(params.getPageNum(), params.getPageSize());

    // 构造基础查询条件
    var queryWrapper = lambdaQuery()
            .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<Long> userIds = Collections.emptyList();
    Map<Long, String> userIdToMobileMap = new HashMap<>();

    // 若提供了手机号码，则查找匹配用户 ID 列表用于过滤优惠券
    if (CommUtil.isNotEmptyAndNull(params.getMobilePhone())) {
        List<User> matchedUsers = userService.lambdaQuery()
                .like(User::getMobilePhone, params.getMobilePhone())
                .list();
        userIds = matchedUsers.stream().map(User::getId).toList();
        userIdToMobileMap.putAll(matchedUsers.stream()
                .collect(Collectors.toMap(User::getId, User::getMobilePhone)));
    }

    // 应用用户 ID 过滤条件
    queryWrapper.in(CommUtil.isNotEmptyAndNull(userIds), UserCoupon::getUserId, userIds);

    // 执行主查询
    List<UserCoupon> userCoupons = queryWrapper.list();

    // 补充未通过手机号查询的所有相关用户信息
    if (!userCoupons.isEmpty()) {
        Set<Long> allUserIds = userCoupons.stream().map(UserCoupon::getUserId).collect(Collectors.toSet());
        if (!allUserIds.isEmpty() && userIdToMobileMap.size() < allUserIds.size()) {
            List<User> additionalUsers = userService.lambdaQuery()
                    .in(User::getId, allUserIds)
                    .list();
            for (User u : additionalUsers) {
                userIdToMobileMap.putIfAbsent(u.getId(), u.getMobilePhone());
            }
        }
    }

    // 构建 VO 列表
    List<UserCouponVo> voList = userCoupons.stream().map(coupon -> {
        UserCouponVo vo = new UserCouponVo();
        BeanUtils.copyProperties(coupon, vo);
        vo.setMobilePhone(userIdToMobileMap.get(coupon.getUserId()));
        return vo;
    }).toList();

    // 构造最终结果集
    PageBean<UserCoupon> rawPageResult = new PageBean<>(userCoupons);
    PageBean<UserCouponVo> resultPage = new PageBean<>();
    BeanUtils.copyProperties(rawPageResult, resultPage);
    resultPage.setList(voList);

    return resultPage;
}


    @Override
    public void collectCoupon(Long couponId) {
        // 手动切换数据源
        DynamicDataSourceContextHolder.push("db-admin");
        // 优惠券状态校验
        var coupon = couponService.lambdaQuery()
                .eq(Coupon::getId, couponId)
                .in(Coupon::getStatus, Coupon.STATUS_未开始, Coupon.STATUS_进行中)
                .one();

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

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

        // 重复领取校验
        var userId = StpUtil.getLoginIdAsLong();
        var exist = redisTemplate.opsForSet().isMember(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);
        if (Boolean.TRUE.equals(exist)) {
            DynamicDataSourceContextHolder.poll();
            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);

        DynamicDataSourceContextHolder.poll();

        // 存入缓存和数据库
        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数据，优惠券失效或者使用之后该做什么操作？
    }

    /**
     * 通过订单号查询订单使用的优惠券信息
     *
     * @param startChargeSeq
     * @return
     */
    @Override
    public UserOrderCouponVo getUserOrderCoupon(String startChargeSeq) {
        var userId = StpUtil.getLoginIdAsLong();
        MPJLambdaWrapper<UserCoupon> wrapper = JoinWrappers.lambda(UserCoupon.class)
                .selectAsClass(UserCoupon.class, UserOrderCouponVo.class)
                .selectAs(OrderCoupon::getStartChargeSeq, UserOrderCouponVo::getStartChargeSeq)
                .selectAs(OrderCoupon::getDiscountAmount, UserOrderCouponVo::getOrderDiscountAmount)
                .rightJoin(OrderCoupon.class, on -> on.eq(OrderCoupon::getUserCouponId, UserCoupon::getId).eq(OrderCoupon::getUserId, UserCoupon::getUserId))
                .eq(UserCoupon::getUsageStatus, UserCoupon.USAGE_STATUS_已使用)
                .eq(OrderCoupon::getStartChargeSeq, startChargeSeq)
                .eq(OrderCoupon::getUserId, userId)
                .eq(OrderCoupon::getStatus, OrderCoupon.STATUS_使用成功);
        return selectJoinOne(UserOrderCouponVo.class, wrapper);
    }

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

}
