package com.izouma.nineth.service;

import com.alibaba.fastjson.JSONObject;
import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.Collection;
import com.izouma.nineth.domain.Order;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.dto.PageWrapDTO;
import com.izouma.nineth.dto.PushMsgDTO;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.event.CreateOrderEvent;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockException;
import com.izouma.nineth.lock.RedisLockable;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.pay.PayHelper;
import com.izouma.nineth.service.pay.UniformPayUtil;
import com.izouma.nineth.service.rewardpoints.UserIntegralChangeLogService;
import com.izouma.nineth.utils.IPUtils;
import com.izouma.nineth.utils.JpaUtils;
import com.izouma.nineth.utils.SecurityUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@AllArgsConstructor
@Slf4j
public class OrderService {

    private OrderRepo                     orderRepo;
    private CollectionRepo                collectionRepo;
    private UserAddressRepo               userAddressRepo;
    private UserRepo                      userRepo;
    private AssetService                  assetService;
    private SysConfigService              sysConfigService;
    private AssetRepo                     assetRepo;
    private UserCouponRepo                userCouponRepo;
    private CollectionService             collectionService;
    private RedisTemplate<String, Object> redisTemplate;
    private CommissionRecordRepo          commissionRecordRepo;
    private GeneralProperties             generalProperties;
    private SnowflakeIdWorker             snowflakeIdWorker;
    private RocketMQTemplate              rocketMQTemplate;
    private UserWareHouseRepo userWareHouseRepo;

    private DivMoneyRepo divMoneyRepo;

    private PaymentInfoRepo paymentInfoRepo;

    private PaymentInfoService paymentInfoService;

    private UniformPayUtil uniformPayUtil;

    private PayHelper payHelper;

    private final EntityManager entityManager;

    private final SysConfigService sysConfigServiceImpl;

    private UserFundChangeLogService userFundChangeLogService;

    private UserIntegralChangeLogService userIntegralChangeLogService;

    private PushService pushService;

    /**
     * 列表
     * @param pageQuery
     * @return
     */
    public PageWrapDTO<Order> all(PageQuery pageQuery) {
        String officalCollectionIdStr = Objects.toString(pageQuery.getQuery().remove("officialCollectionId"),"");

        Specification<Order> specification = JpaUtils.toSpecification(pageQuery, Order.class);
        //其他条件
        specification = specification.and((root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if(StringUtils.isNotEmpty(officalCollectionIdStr)){
                Subquery<Long> assetExists = query.subquery(Long.class);
                Root<Asset> subroot = assetExists.from(Asset.class);
                assetExists.select(subroot.get("id"));
                Predicate wherePre = builder.conjunction();
                wherePre.getExpressions().add(builder.equal(subroot.get("id"), root.get("assetId")));
                wherePre.getExpressions().add(builder.equal(subroot.get("collectionId"), officalCollectionIdStr));
                assetExists.where(wherePre);
                predicates.add(builder.exists(assetExists));
            }
            return builder.and(predicates.toArray(new Predicate[]{}));
        });

        Page<Order> page = orderRepo.findAll(specification, JpaUtils.toPageRequest(pageQuery));
        PageWrapDTO<Order> pageWrapDTO = new PageWrapDTO<>(page.toList(), page.getPageable(), page.getTotalElements());
        //设置失效时间
        pageWrapDTO.forEach(item -> {
            if(item.getCreatedAt() != null){
                LocalDateTime expireTime = payHelper.getExpireTime(item.getCreatedAt());
                item.setExpireTime(expireTime);
            }
        });

        BigDecimal totalAmount = sumAmount(specification);
        pageWrapDTO.setTotalAmount(totalAmount);

        return pageWrapDTO;
    }


    /**
     * 获取订单信息
     * @param orderId
     * @return
     */
    public Order getOrderInfo(Long orderId){
        Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单未找到"));
        LocalDateTime expireTime = payHelper.getExpireTime(order.getCreatedAt());
        order.setExpireTime(expireTime);
        return order;
    }


    /**
     * 排队抢购
     * @param userId
     * @param collectionId
     * @param qty
     * @param addressId
     * @param userCouponId
     * @param invitor
     * @return
     */
    @RedisLockable(prefix = RedisKeys.MQ_ORDER_LOCK, key="#userId + '_' + #collectionId")
    public String mqCreate(Long userId, Long collectionId, int qty, Long addressId, Long userCouponId,List<Long> couponIds, Long invitor) {
        collectionService.increaseOrderStatis(collectionId);
        //只有订单取消和创建订单失败时才能恢复库存，宁可少发，不能多发
        Integer stock = collectionService.getStockCache(collectionId);
        if (stock <= 0) {
            throw new BusinessException("很遗憾，藏品已售罄");
        }
        if ((userCouponId != null && (couponIds == null || couponIds.isEmpty()))) {
            couponIds = new ArrayList<>();
            couponIds.add(userCouponId);
        }
        if (couponIds == null){
            couponIds = new ArrayList<>();
        }
        stock = collectionService.increaseStockCache(collectionId, -qty);
        if (stock < 0) {
            collectionService.increaseStockCache(collectionId, qty);
            throw new BusinessException("很遗憾，藏品已售罄");
        }
        //调整为10秒，防止长时间占用线程资源
        Long id = snowflakeIdWorker.nextId();
        SendResult result = rocketMQTemplate.syncSend(generalProperties.getCreateOrderTopic(),
                new CreateOrderEvent(id, userId, collectionId, qty, addressId, couponIds, invitor,IPUtils.getIpAddr()), 10000);

        log.info("发送订单到队列: {}, result={}", id, result);
        return String.valueOf(id);
    }

    /**
     * 创建订单，入数据库
     * @return
     */
    @Transactional
    public Order create(CreateOrderEvent event) {
        Long userId = event.getUserId();
        Long collectionId = event.getCollectionId();
        int qty = event.getQty();
        Long addressId = event.getAddressId();
        List<Long> userCouponIds = event.getUserCouponIds();
        Long invitor = event.getInvitor();
        Long orderId = event.getId();

        long beforeTime = System.currentTimeMillis();
        User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("用户不存在"));
        //不锁定记录，不修改藏品对象
        Collection collection = collectionRepo.findById(collectionId).orElseThrow(new BusinessException("藏品不存在"));
        //User minter = userRepo.findById(collection.getMinterId()).orElseThrow(new BusinessException("铸造者不存在"));
        List<UserCoupon> coupons = new ArrayList<>();
        //分别验证兑换券
        for (Long couponId : userCouponIds) {
            if (couponId != null) {
                UserCoupon coupon = userCouponRepo.findById(couponId).orElseThrow(new BusinessException("兑换券不存在"));
                if (coupon.isUsed()) {
                    throw new BusinessException("该兑换券已使用");
                }
                if (coupon.isLimited() && !coupon.getCollectionIds().contains(collectionId)) {
                    throw new BusinessException("该兑换券不可用");
                }
                coupons.add(coupon);
            }
        }
        //验证消耗兑换券量和购买量
        if(!coupons.isEmpty() &&coupons.size()< qty){
            throw new BusinessException("您的兑换券不足以购买您当前选择的购买量");
        }
        if (!collection.isOnShelf()) {
            throw new BusinessException("藏品已下架");
        }
        if (qty > collection.getStock()) {
            throw new BusinessException("库存不足");
        }
        if (!collection.isSalable()) {
            throw new BusinessException("该藏品当前不可购买");
        }

        //转让交易判断
        if (collection.getSource() == CollectionSource.TRANSFER) {
            Asset asset = assetRepo.findById(collection.getAssetId()).orElseThrow(new BusinessException("资产不存在"));
            if (asset.getStatus() != AssetStatus.NORMAL) {
                throw new BusinessException("藏品正在交易中");
            }

            if(asset.getUserId().equals(userId)){
                throw new BusinessException("不能购买自己发布的藏品");
            }

            asset.setStatus(AssetStatus.TRADING);
            assetRepo.save(asset);
            //不下架，交易中的也显示
            //collectionRepo.setOnShelf(collection.getId(), false);
        }
        List<Collection> list = new ArrayList<>();
        if (!collectionService.filter(list, user)){
            throw new BusinessException("当前还未开售");
        }

        UserAddress userAddress = null;
        if (addressId != null) {
            userAddress = userAddressRepo.findById(addressId).orElseThrow(new BusinessException("地址信息不存在"));
        }
        List<JSONObject> userWareHouseIds = new ArrayList<>();
        if (collection.isScheduleSale() && collection.getStartTime().isAfter(LocalDateTime.now())) {
            List<UserWareHouse> userWareHouse = collectionService.getAdvancePurchaseTime(user.getId(), collection);
            if (userWareHouse.isEmpty()) {
                throw new BusinessException("当前还未开售");
            }
            int preBuyNum = userWareHouse.stream().mapToInt(UserWareHouse::getAdvancePurchaseCount).sum();
            if (preBuyNum - qty < 0) {
                throw new BusinessException("您的优先购可购买次数不足");
            } else {
                //当前已消耗量
                int costPurchase = 0;
                for (UserWareHouse ac : userWareHouse) {
                    //消耗品扣除次数
                    if (ItemType.PERPETUAL_CERTIFICATE.equals(ac.getItemName())
                            || ItemType.CONSUMABLE_ASSIGN_CERTIFICATE.equals(ac.getItemName())
                            || ItemType.CONSUMABLE_CERTIFICATE.equals(ac.getItemName())) {
                        //当前凭证不足以消耗购买量 则为当前凭证可购买量
                        int number = (qty - costPurchase - ac.getAdvancePurchaseCount() > 0) ? ac.getAdvancePurchaseCount() : qty - costPurchase;
                        if (number > 0) {
                            costPurchase = costPurchase + number;
                            ac.setAdvancePurchaseCount(ac.getAdvancePurchaseCount() - number);
                            ac.setDisabled(ac.getAdvancePurchaseCount() > 0);
                            userWareHouseRepo.save(ac);
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("id", ac.getId());
                            jsonObject.put("num", number);
                            userWareHouseIds.add(jsonObject);
                        }
                    }
                }

            }
        }

        if(userWareHouseIds.isEmpty() && collection.getSource() != CollectionSource.TRANSFER){
            //首发藏品，限制购买次数
            Integer collectionLimitBuyCount = collection.getLimitBuyCount();
            if(collectionLimitBuyCount == null){
                //默认限购10份
                collectionLimitBuyCount = 10;
            }
            if(collectionLimitBuyCount > 0){
                Integer validCount = orderRepo.countValidOrder(userId, collectionId);
                validCount += qty;//总的购买数量
                if(validCount > collectionLimitBuyCount){
                    throw new BusinessException("每人只能购买" + collectionLimitBuyCount + "份");
                }
            }

        }

        BigDecimal gasPrice = sysConfigService.getBigDecimal(SysConstants.GAS_FEE);
        Order order = Order.builder()
                .id(Optional.ofNullable(orderId).orElse(snowflakeIdWorker.nextId()))
                .userId(userId)
                .collectionId(collectionId)
                .name(collection.getName())
                .pic(collection.getPic())
                .detail(collection.getDetail())
                .properties(collection.getProperties())
                .category(collection.getCategory())
                .canResale(collection.isCanResale())
                .royalties(collection.getRoyalties())
                .serviceCharge(collection.getServiceCharge())
                .type(collection.getType())
                .source(collection.getSource())
                .minterId(collection.getMinterId())
                .minter(collection.getMinter())
                .minterAvatar(collection.getMinterAvatar())
                .qty(qty)
                .price(collection.getPrice())
                .gasPrice(gasPrice)
                .totalPrice(collection.getPrice().multiply(BigDecimal.valueOf(qty)).add(gasPrice.multiply(new BigDecimal(qty))))
                .contactName(Optional.ofNullable(userAddress).map(UserAddress::getName).orElse(null))
                .contactPhone(Optional.ofNullable(userAddress).map(UserAddress::getPhone).orElse(null))
                .address(Optional.ofNullable(userAddress).map(u ->
                        u.getProvinceId() + " " + u.getCityId() + " " + u.getDistrictId() + " " + u.getAddress())
                        .orElse(null))
                .status(OrderStatus.NOT_PAID)
                .assetId(collection.getAssetId())
                .couponIds(userCouponIds)
                .invitor(invitor)
                .projectId(collection.getProjectId())
                .ip(event.getFromIp())
                .build();
        if (!userWareHouseIds.isEmpty()){
            order.setUserWareHouseList(userWareHouseIds);
        }
        //根据兑换券 计算gas费
        if (!coupons.isEmpty()) {
            for (UserCoupon coupon: coupons
                 ) {
                coupon.setUsed(true);
                coupon.setUseTime(LocalDateTime.now());
                userCouponRepo.save(coupon);
            }
            long needGasNum = coupons.stream().filter(UserCoupon::isNeedGas).count();
            order.setTotalPrice(order.getGasPrice().multiply(new BigDecimal(needGasNum)));
        }

        order = orderRepo.save(order);
        //价格为0，默认支付成功
        if (order.getTotalPrice().compareTo(BigDecimal.ZERO) == 0) {
            notifyOrder(order.getId(), PayMethod.WEIXIN, null);
        }

        //rocketMQTemplate.syncSend(generalProperties.getUpdateStockTopic(), collectionId, 10000);
        //减少库存
        collectionRepo.increaseStock(collection.getId(), -order.getQty());
        //二次校验，防止超发
        Integer stock = collectionRepo.getStock(collection.getId());
        if(stock < 0){
            throw new BusinessException("剩余库存不足");
        }

        log.info("订单创建完成, id={}, {}ms", order.getId(), System.currentTimeMillis() - beforeTime);

        //创建订单后记录用户锁单数
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.USER_LOCK_ORDER_NUMBER + order.getUserId());
        Integer lockNum = (Integer) ops.get();
        if (lockNum == null) {
            //第一次下单，初始化计数周期
            Boolean success = ops.setIfAbsent(1, sysConfigServiceImpl.getInt(SysConstants.LOCK_ORDER_COUNT_INTERVAL), TimeUnit.HOURS);
            log.info("初始化用户锁单数：用户{}, 锁单数量：{}, 返回结果：{}", order.getUserId(), ops.get(), success);
        }else {
            lockNum = ops.increment(1).intValue();
            if(lockNum >=  sysConfigService.getInt(SysConstants.LOCK_ORDER_LIMIT_NUMBER)){
                //达到锁单限制,锁定时间初始化
                ops.expire(sysConfigService.getInt(SysConstants.LOCK_ORDER_PUNISH_TIME), TimeUnit.HOURS);
            }
        }
        return order;
    }



    /**
     * 订单回调
     * @param orderId
     * @param payMethod
     * @param transactionId
     */
    @RedisLockable(prefix = RedisKeys.ORDER_LOCK, key="#orderId", expiration = 360)
    @Transactional
    public void notifyOrder(Long orderId, PayMethod payMethod, String transactionId) {
        //修改对象，提前锁定
        Order order = orderRepo.findByIdForUpdate(orderId).orElseThrow(new BusinessException("订单不存在"));
        User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在"));
        if(order.getOrderNo() != null){
            PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(order.getOrderNo()).orElseThrow(new BusinessException("未找到订单的支付记录"));
            if(paymentInfo.getStatus() != PayStatus.HAVE_PAID){
                throw new BusinessException("支付状态错误 " + paymentInfo.getStatus());
            }
        }

        if (order.getStatus() == OrderStatus.CANCELLED) {
            //仅仅设置待退款状态，后续由人工或定时任务处理
            paymentInfoService.setPendingRefund(order.getOrderNo(),"订单超时退款" );
            throw new BusinessException("订单已被取消");
        }

        if (order.getStatus() != OrderStatus.NOT_PAID) {
            throw new BusinessException("订单状态错误 " + order.getStatus());
        }

        order.setStatus(OrderStatus.PROCESSING);
        order.setPayTime(LocalDateTime.now());
        order.setTransactionId(transactionId);
        order.setPayMethod(payMethod);
        //提前计算
        commission(order);
        //提前执行sql,防止后续查询不到数据
        orderRepo.saveAndFlush(order);
        //不需要锁定，提高响应处理
        Collection collection = collectionRepo.findById(order.getCollectionId())
                .orElseThrow(new BusinessException("藏品不存在"));
        if (collection.getSource() == CollectionSource.TRANSFER) {
            Asset asset = assetRepo.findById(collection.getAssetId()).orElseThrow(new BusinessException("藏品不存在"));
            assetService.transfer(asset, order.getPrice(), user, OperationType.TRANSFER.getDescription(), order.getId());
            List<Long> collectionIds = collectionRepo.findAllByAssetId(collection.getAssetId());
            if (CollectionUtils.isNotEmpty(collectionIds)) {
                log.info("删除collection {}", collectionIds);
                collectionRepo.deleteAllByIdIn(collectionIds);
            } else {
                log.info("删除collection {}", collection.getId());
                collectionRepo.delete(collection);
            }
            //资产创建成功时才记录钱包流水，防止退款影响
            divMoneyRepo.findByOrderId(orderId).forEach(item -> {
                if (item.getUserId() != null && item.getUserFundAccountId() != null) {
                    userFundChangeLogService.createByIncome(item);
                }
            });
        } else {
            if (order.getType() == CollectionType.BLIND_BOX && !collection.isVariableType()) {
                log.info("开始盲盒抽卡 orderId: {}, collectionId: {}", orderId, collection.getId());
                try {
                    BlindBoxItem winItem = collectionService.draw(collection.getId());
                    order.setWinCollectionId(winItem.getCollectionId());
                    orderRepo.save(order);
                    for (int i = 0; i < order.getQty(); i++) {
                        assetService.createAsset(collection, winItem, user, order.getId(), order.getPrice(), OperationType.SELL.getDescription());
                    }
                    log.info("抽卡成功 orderId: {}, collectionId: {}, winCollectionId: {}", orderId, collection.getId(), winItem.getCollectionId());
                } catch (RedisLockException redisLockException) {
                    //抛出错误，重新抽取
                    throw redisLockException;
                } catch (Exception err) {
                    log.info("抽卡失败退款 orderId: {}, reason: {}", orderId, err.getMessage());
                    //仅仅设置待退款状态，后续由人工或定时任务处理
                    paymentInfoService.setPendingRefund(order.getOrderNo(), "抽卡失败退款");
                    //抛异常，修改回退
                    throw err;
                }
            } else {
                for (int i = 0; i < order.getQty(); i++) {
                    assetService.createAsset(collection, user, order.getId(), order.getPrice(), OperationType.SELL.getDescription());
                }
            }
        }
        if(collection.getAssetId() == null){
            //增加销量
            collectionRepo.increaseSale(collection.getId(), order.getQty());
        }

        //获得积分
        BigDecimal consumeRatio = sysConfigService.getBigDecimal(SysConstants.TRANSFORM_INTEGRAL_RATIO);
        long obtainIntegral = order.getTotalPrice().multiply(consumeRatio).longValue();
        if(obtainIntegral > 0){
            UserIntegralChangeLog changeLog = userIntegralChangeLogService.createByChangeType(IntegralChangeType.CONSUME, order.getUserId(), obtainIntegral);
            changeLog.setSourceId(orderId);
        }

        //通知卖出成功信息
        notificationSellerMsg(order);

        //完成支付订单后 减少锁单量
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.USER_LOCK_ORDER_NUMBER + order.getUserId());
        Integer lockOrderNum = (Integer) ops.get();
        if (lockOrderNum != null && lockOrderNum > 0) {
            lockOrderNum = ops.decrement(1).intValue();
            if (lockOrderNum < sysConfigService.getInt(SysConstants.LOCK_ORDER_LIMIT_NUMBER)){
                //未达到锁定限制，使用计数周期
                ops.expire(sysConfigServiceImpl.getInt(SysConstants.LOCK_ORDER_COUNT_INTERVAL), TimeUnit.HOURS);
            }
        }
    }



    /**
     * 取消订单
     *
     */
    @RedisLockable(prefix = RedisKeys.ORDER_LOCK, key="#orderId", expiration = 360)
    @Transactional
    public void cancel(Long orderId) {
        log.info("尝试取消订单：{}", orderId);
        //修改对象，提前锁定
        Order order = orderRepo.findByIdForUpdate(orderId).orElseThrow(new BusinessException("订单不存在"));
        if (order.getStatus() != OrderStatus.NOT_PAID) {
            throw new BusinessException("不是待支付订单无法取消:" + order.getId());
        }

        //不能取消已付款的记录
        Integer pendingCount = paymentInfoRepo.countPendingStatus(orderId);
        if(pendingCount > 0){
            throw new BusinessException("处理中的订单无法取消：" + order.getId());
        }

        Integer havePaidCount = paymentInfoRepo.countHavePaidStatus(orderId);
        if(havePaidCount > 0){
            throw new BusinessException("已付款的订单无法取消：" + order.getId());
        }

        List<JSONObject> userWareHouseId = order.getUserWareHouseList();
        if (userWareHouseId != null && !userWareHouseId.isEmpty()){
            //恢复优先购次数
            userWareHouseId.forEach(item -> {
                Optional<UserWareHouse> ac = userWareHouseRepo.findById(item.getLong("id"));
                ac.ifPresent(e->{
                    e.setAdvancePurchaseCount(e.getAdvancePurchaseCount()+item.getInteger("num"));
                    e.setDisabled(e.getAdvancePurchaseCount()>0);
                    userWareHouseRepo.save(e);
                });
            });
        }

        //逻辑删除分账信息
        divMoneyRepo.softDeleteByOrderId(order.getId());
        order.setStatus(OrderStatus.CANCELLED);
        order.setCancelTime(LocalDateTime.now());
        orderRepo.save(order);

        if (order.getCouponIds() != null) {
            order.getCouponIds().forEach(item ->
                    userCouponRepo.findById(item).ifPresent(coupon -> {
                coupon.setUsed(false);
                coupon.setUseTime(null);
                userCouponRepo.save(coupon);
            }));
        }
        //不锁定记录，不修改藏品对象
        Collection collection = collectionRepo.findById(order.getCollectionId())
                .orElse(null);
        if(collection != null){
            CollectionSource source = collection.getSource();
            if (source == CollectionSource.TRANSFER) {
                Asset asset = assetRepo.findById(order.getAssetId()).orElse(null);
                if (asset != null) {
                    asset.setStatus(AssetStatus.NORMAL);
                    assetRepo.save(asset);
                }else{
                    log.error("订单取消有误，订单资产不存在，订单ID:{}", order.getId());
                }

                collectionRepo.setOnShelf(order.getCollectionId(), true);
            }
        }
        //恢复库存
        collectionRepo.increaseStock(order.getCollectionId(), order.getQty());
        collectionService.increaseStockCache(order.getCollectionId(), order.getQty());
        Integer restStock = collectionService.getStockCache(order.getCollectionId());
        log.info("成功取消订单：{}, 藏品ID:{}, 剩余缓存库存：{}", order.getId(), order.getCollectionId(), restStock);
    }


    public synchronized void addSales(Long userId) {
        if (userId != null) {
            userRepo.findById(userId).ifPresent(user -> {
                user.setSales(user.getSales() + 1);
                userRepo.save(user);
            });
        }
    }

    public void setNumber() {
        for (Collection collection : collectionRepo.findAll()) {
            if (collection.getSource() != CollectionSource.OFFICIAL) continue;
            collection.setCurrentNumber(0);
            collectionRepo.save(collection);
            for (Asset asset : assetRepo.findByCollectionId(collection.getId())) {
                if (asset.getStatus() == AssetStatus.GIFTED || asset.getStatus() == AssetStatus.TRANSFERRED) {

                } else {
                    asset.setNumber(assetService.getNextNumber(collection.getId()));
                    assetRepo.save(asset);
                }
            }
        }
    }


    public void commission(Order order) {
        if (order.getInvitor() != null) {
            userRepo.findById(order.getInvitor()).ifPresent(user -> {
                BigDecimal shareRatio = user.getShareRatio();
                if (shareRatio != null && shareRatio.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal totalPrice = order.getTotalPrice().subtract(order.getGasPrice());
                    BigDecimal shareAmount = totalPrice.multiply(shareRatio)
                            .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
                    commissionRecordRepo.save(CommissionRecord.builder()
                            .orderId(order.getId())
                            .totalPrice(totalPrice)
                            .nickname(user.getNickname())
                            .userId(user.getId())
                            .shareRatio(user.getShareRatio())
                            .phone(user.getPhone())
                            .shareAmount(shareAmount)
                            .build());
                }
            });
        }
    }

    public Object queryCreateOrder(String id) {
        Object res = redisTemplate.opsForValue().get(RedisKeys.CREATE_ORDER + id);
        if (res instanceof Map && MapUtils.getBooleanValue((Map) res, "success", false)) {
            Order order = (Order) MapUtils.getObject((Map) res, "data");
            if (!SecurityUtils.getAuthenticatedUser().getId().equals(order.getUserId())) {
                log.error("queryCreateOrder userId错误 requestUserId={} orderUserId={}",
                        SecurityUtils.getAuthenticatedUser().getId(), order.getUserId());
                return null;
            }
        }
        return res;
    }


    /**
     * 获取待取消订单
     * @return
     */
    public List<Long> findWaitingCancelList(){
        //使用配置的间隔时间
        int expireInterval = payHelper.getExpireInterval();
        LocalDateTime beforeDate = LocalDateTime.now().minusMinutes(expireInterval);
        return orderRepo.findWaitingCancelList(OrderStatus.NOT_PAID, beforeDate);
    }

    /**
     * 统计用户销量
     * @param userId
     * @return
     */
    public Integer countSales(Long userId){
        return orderRepo.countSales(userId);
    }


    /**
     * 批量退款
     * @return
     */
    @Transactional
    public List<String> batchRefund(List<String> orderNoList) throws Exception{
        for(String orderNo : orderNoList){
            PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("支付信息未找到:" + orderNo ));
            if(paymentInfo.getStatus() != PayStatus.PENDING_REFUND){
                throw new BusinessException("订单号“"+orderNo+"”的支付状态不是待退款状态");
            }

            Order order = orderRepo.findById(paymentInfo.getOrderId()).orElseThrow(new BusinessException("订单记录未找到：" + paymentInfo.getOrderId()));
            if(order.getStatus() != OrderStatus.CANCELLED){
                throw new BusinessException("订单号“"+orderNo+"”的订单状态不是已取消状态");
            }

            uniformPayUtil.refund(orderNo, paymentInfo.getRefundReason());
        }

        return orderNoList;

    }

    /**
     * 检查并自动退款
     * @param orderId
     */
    @Transactional
    public void checkAndAutoRefund(Long orderId){
        //修改对象，提前锁定
        Order order = orderRepo.findByIdForUpdate(orderId).orElse(null);
        if(order != null && order.getOrderNo() != null){
            PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(order.getOrderNo()).orElse(null);
            if(paymentInfo != null && paymentInfo.getStatus() == PayStatus.PENDING_REFUND){
                //需要退款，直接执行退款逻辑
                try {
                    uniformPayUtil.refund(paymentInfo.getOrderNo(), paymentInfo.getRefundReason());
                } catch (Exception e) {
                    log.error("自动退款失败，orderNo:{}, error:{}", paymentInfo.getOrderNo(), e.getMessage());
                }
            }
        }
    }

    public BigDecimal sumAmount(Specification specification) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<BigDecimal> criteriaQuery = criteriaBuilder.createQuery(BigDecimal.class);
        Root<Order> root = criteriaQuery.from(Order.class);
        criteriaQuery.select(
                criteriaBuilder.sum(root.get("totalPrice"))
        );
        Predicate predicate = specification.toPredicate(root, criteriaQuery, criteriaBuilder);
        criteriaQuery.where(predicate);
        TypedQuery<BigDecimal> query = entityManager.createQuery(criteriaQuery);
        return query.getSingleResult();
    }


    /**
     * 通知卖出信息
     * @param order
     */
    public void notificationSellerMsg(Order order){
        Long assetId = order.getAssetId();
        if(assetId != null){
            try{
                Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("卖家资产未找到"));
                User seller = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("卖家信息未找到"));
                if(StringUtils.isNotEmpty(seller.getAppClientId() )){
                    PushMsgDTO pushMsgDTO = new PushMsgDTO();
                    pushMsgDTO.setClientId(seller.getAppClientId());
                    pushMsgDTO.setTitle("藏品卖出通知");
                    pushMsgDTO.setContent("您寄售的“"+asset.getName()+"“已成功卖出");
                    pushService.pushNotification(pushMsgDTO);
                }
            }catch(Exception e){
                log.error("卖出通知消息发送失败", e);
            }
        }

    }

}
