
package com.tmerclub.cloud.coupon.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.tmerclub.cloud.api.coupon.constant.UserCouponStatus;
import com.tmerclub.cloud.api.coupon.dto.LockCouponDTO;
import com.tmerclub.cloud.api.order.constant.OrderStatus;
import com.tmerclub.cloud.api.order.feign.OrderFeignClient;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.order.bo.OrderStatusBO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.coupon.mapper.CouponLockMapper;
import com.tmerclub.cloud.coupon.mapper.CouponUserMapper;
import com.tmerclub.cloud.coupon.model.CouponLock;
import com.tmerclub.cloud.coupon.service.CouponLockService;
import com.tmerclub.cloud.coupon.service.CouponUserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 优惠券使用记录
 *
 * @author tmerclub
 * @date 2020-12-28 10:04:50
 */
@Service
public class CouponLockServiceImpl implements CouponLockService {

    @Autowired
    private CouponLockMapper couponLockMapper;
    @Autowired
    private CouponUserService couponUserService;
    @DubboReference
    private OrderFeignClient orderFeignClient;
    @Autowired
    private RocketMQTemplate couponMqTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponseEntity<Void> lockCoupon(List<LockCouponDTO> lockCouponParams) {
        List<CouponLock> couponLocks = Lists.newArrayList();
        Long userId = AuthUserContext.get().getUserId();
        List<Long> userCouponIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        Set<Long> orderIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        for (LockCouponDTO lockCouponParam : lockCouponParams) {
            CouponLock couponLock = new CouponLock();
            couponLock.setAmount(lockCouponParam.getReduceAmount());
            // 获取用户优惠券id
            couponLock.setCouponUserId(lockCouponParam.getCouponUserId());
            userCouponIds.add(lockCouponParam.getCouponUserId());
            couponLock.setUserId(userId);
            couponLock.setOrderIds(lockCouponParam.getOrderIds());
            if (couponLock.getOrderIds().contains(StrUtil.COMMA)) {
                for (String orderId : couponLock.getOrderIds().split(StrUtil.COMMA)) {
                    orderIds.add(Long.valueOf(orderId));
                }
            } else {
                orderIds.add(Long.valueOf(couponLock.getOrderIds()));
            }
            //优惠券记录为冻结状态
            couponLock.setStatus(0);

            couponLocks.add(couponLock);
        }
        // 批量保存使用记录
        couponLockMapper.saveBatch(couponLocks);
        // 批量将用户的优惠券变成已使用状态
        couponUserService.batchUpdateUserCouponStatus(UserCouponStatus.USED.getValue(), userCouponIds);

        // 发送消息一个小时后解锁优惠券(包括哪些订单)
        SendStatus sendStatus = couponMqTemplate.syncSend(RocketMqConstant.COUPON_UNLOCK_TOPIC, new GenericMessage<>(orderIds), RocketMqConstant.TIMEOUT, RocketMqConstant.CANCEL_ORDER_DELAY_LEVEL + 1).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，发的出去无所谓
            throw new LuckException(ResponseEnum.EXCEPTION, new Object());
        }

        return ServerResponseEntity.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unlockCoupon(List<Long> orderIds) {
        ServerResponseEntity<List<OrderStatusBO>> ordersStatusResponse = orderFeignClient.getOrdersStatus(orderIds);
        if (!ordersStatusResponse.isSuccess()) {
            throw new LuckException(ordersStatusResponse.getMsg());
        }
        List<OrderStatusBO> orderStatusList = ordersStatusResponse.getData();
        List<Long> needCouponUserIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (OrderStatusBO orderStatusBO : orderStatusList) {
            // 该订单没有下单成功，或订单已取消，赶紧解锁库存
            if (orderStatusBO.getStatus() == null || Objects.equals(orderStatusBO.getStatus(), OrderStatus.CLOSE.value())) {
                List<Long> couponUserIds = couponLockMapper.listCouponUserIdsByOrderId(orderStatusBO.getOrderId());
                needCouponUserIds.addAll(couponUserIds);
            }
        }

        if (CollectionUtil.isEmpty(needCouponUserIds)) {
            return;
        }

        // 将锁定状态标记为已解锁
        int updateStatus = couponLockMapper.unLockByIds(needCouponUserIds);
        if (updateStatus == 0) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        // 批量将用户的优惠券变成未使用状态
        couponUserService.batchUpdateUserCouponStatus(UserCouponStatus.EFFECTIVE.getValue(), needCouponUserIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markerCouponUse(List<Long> orderIds) {
        couponLockMapper.markerCouponUse(orderIds);
    }

    @Override
    public void reductionCoupon(Long orderId) {
        List<CouponLock> couponLocks = couponLockMapper.getUserCouponIdByOrderId(String.valueOf(orderId));
        Iterator<CouponLock> iterator = couponLocks.iterator();
        while (iterator.hasNext()) {
            CouponLock couponLock = iterator.next();
            if (!couponLock.getOrderIds().contains(StrUtil.COMMA)) {
                continue;
            }
            // 多个订单，需要校验是否全部退款成功
            List<Long> orderIds = Arrays.stream(couponLock.getOrderIds().split(StrUtil.COMMA)).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            orderIds.remove(orderId);
            ServerResponseEntity<List<OrderStatusBO>> ordersStatusResponse = orderFeignClient.getOrdersStatus(orderIds);
            if (!ordersStatusResponse.isSuccess()) {
                throw new LuckException(ordersStatusResponse.getMsg());
            }
            List<OrderStatusBO> orderStatusList = ordersStatusResponse.getData();
            List<OrderStatusBO> closeList = orderStatusList.stream().filter(status -> Objects.equals(status.getStatus(), OrderStatus.CLOSE.value())).toList();
            if (!Objects.equals(closeList.size(), orderStatusList.size())) {
                // 没有全部退款成功
                iterator.remove();
            }
        }
        if (CollUtil.isNotEmpty(couponLocks)) {
            List<Long> couponUserIds = couponLocks.stream().map(CouponLock::getCouponUserId).collect(Collectors.toList());
            couponUserService.reductionCoupon(couponUserIds);
        }
    }

}
