package com.zanxiang.game.back.serve.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.sd4324530.jtuple.Tuple2;
import com.github.sd4324530.jtuple.Tuple4;
import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAccountIdV3RpcDTO;
import com.zanxiang.advertising.tencent.base.pojo.dto.UserActionV3RpcDTO;
import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetV3Rpc;
import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiOrderMapper;
import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
import com.zanxiang.game.back.serve.pojo.entity.*;
import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
import com.zanxiang.game.back.serve.service.*;
import com.zanxiang.game.back.serve.utils.BackPolicyUtil;
import com.zanxiang.module.util.NumberUtil;
import com.zanxiang.module.util.ObjectUtil;
import com.zanxiang.module.util.exception.BaseException;
import com.zanxiang.module.util.pojo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Service
public class GameTencentAppApiOrderServiceImpl extends ServiceImpl<GameTencentAppApiOrderMapper, GameTencentAppApiOrder>
implements IGameTencentAppApiOrderService {

    @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
    private IUserActionSetV3Rpc userActionSetRpc;
    @Autowired
    private IGameTencentAppApiBackLogService gameTencentAppApiBackLogService;
    @Autowired
    private IGameBackPolicyService gameBackPolicyService;
    @Autowired
    private IGameTencentAppApiUserService gameTencentAppApiUserService;
    @Autowired
    private IGameTencentAppApiOrderSplitLogService gameTencentAppApiOrderSplitLogService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IGameTencentAppCallbackService gameTencentAppCallbackService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean orderBack(GameTencentAppApiOrder orderLog) {
        if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
            // 只要回传 支付行为
            return false;
        }
        GameTencentAppApiUser userLog = gameTencentAppApiUserService.getOne(new LambdaQueryWrapper<GameTencentAppApiUser>()
                .eq(GameTencentAppApiUser::getGameId, orderLog.getGameId())
                .eq(GameTencentAppApiUser::getUserId, orderLog.getUserId())
                .eq(GameTencentAppApiUser::getAdAccountId, orderLog.getAdAccountId())
                .orderByDesc(GameTencentAppApiUser::getCreateTime)
                .last("limit 1")
        );
        if (userLog == null) {
            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.FAILED.getBackStatus())
                    .set(GameTencentAppApiOrder::getBackMoney, orderLog.getRechargeMoney())
                    .set(GameTencentAppApiOrder::getBackMsg, "回传失败！找不到回传用户")
                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
            );
        }

        GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
                orderLog.getIsFirstOrder(),
                orderLog.getPayTime(),
                // 此处使用用户最近一次的重新染色时间
                userLog.getCreateTime(),
                orderLog.getUserId(),
                new TencentOrderBackPolicyCheck(this, gameBackPolicy, userLog, orderLog));
        boolean doBack = backInfo.first;
        Long backMoney = backInfo.second;
        String backMsg = backInfo.third;
        if (!doBack) {
            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
                    .set(GameTencentAppApiOrder::getBackMoney, backMoney)
                    .set(GameTencentAppApiOrder::getBackMsg, backMsg)
                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
            );
        }
        // 拆单
        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
            // 需要拆单
            List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
            for (int i = 0; i < backInfo.fourth.size(); i++) {
                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                splitOrderLogList.add(GameTencentAppApiOrderSplitLog.builder()
                        .backDay(splitOrder.second.toLocalDate())
                        .orderNo(orderLog.getOrderId())
                        .backIndex(i + 1)
                        .backCount(backInfo.fourth.size())
                        .splitMoney(splitOrder.first)
                        .backTime(splitOrder.second)
                        .backStatus(BackStatusEnum.NO.getBackStatus())
                        .createTime(LocalDateTime.now())
                        .build());
            }
            gameTencentAppApiOrderSplitLogService.saveBatch(splitOrderLogList);
            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
                    .set(GameTencentAppApiOrder::getBackMoney, backInfo.second)
                    .set(GameTencentAppApiOrder::getBackMsg, backMsg)
                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
            );
        }

        Tuple2<BackStatusEnum, String> backResult = doCallback(orderLog, orderLog.getPayTime(), backMoney);
        if (StringUtils.isNotBlank(backResult.second)) {
            backMsg = backMsg + ("回传失败：" + backResult.second);
        }
        return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
                .set(GameTencentAppApiOrder::getBackMoney, backMoney)
                .set(GameTencentAppApiOrder::getBackMsg, backMsg)
                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
        );
    }

    @Override
    public boolean tencentOrderReport(OrderReportDTO dto) {
        listByIds(dto.getOrderIds()).stream()
                .filter(order -> !Objects.equals(order.getIsBack(), BackStatusEnum.SUCCESS.getBackStatus()))
                .forEach(orderLog -> {
                    if (dto.getSplitOrder()) {
                        AtomicLong total = new AtomicLong(0);
                        dto.getSplitMoney().forEach(money -> {
                            total.addAndGet(NumberUtil.multiply100(money).longValue());
                        });
                        if (!orderLog.getRechargeMoney().equals(total.get())) {
                            throw new BaseException("订单充值金额和回传金额对不上");
                        }
                        log.error("手动拆单回传：{}-{}", orderLog.getId(), StringUtils.join(dto.getSplitMoney(), ","));
                        List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(dto.getSplitMoney().size());
                        LocalDateTime beginTime = LocalDateTime.now();
                        long backMoneyTotal = 0L;
                        for (int i = 0; i < dto.getSplitMoney().size(); i++) {
                            long backMoney = NumberUtil.multiply100(dto.getSplitMoney().get(i)).longValue();
                            LocalDateTime backTime = beginTime;
                            backMoneyTotal += backMoney;
                            splitOrderLogList.add(GameTencentAppApiOrderSplitLog.builder()
                                    .backDay(backTime.toLocalDate())
                                    .orderNo(orderLog.getOrderId())
                                    .backIndex(i + 1)
                                    .backCount(dto.getSplitMoney().size())
                                    .splitMoney(backMoney)
                                    .backTime(backTime)
                                    .backStatus(BackStatusEnum.NO.getBackStatus())
                                    .createTime(LocalDateTime.now())
                                    .build());
                            beginTime = beginTime.plusMinutes(RandomUtils.nextInt(dto.getBetweenMinuteMin(), dto.getBetweenMinuteMax()));
                        }
                        gameTencentAppApiOrderSplitLogService.saveBatch(splitOrderLogList);
                        update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                                .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
                                .set(GameTencentAppApiOrder::getBackMoney, backMoneyTotal)
                                .set(GameTencentAppApiOrder::getBackMsg, "手动触发回传（拆单回传）")
                                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
                        );
                    } else {
                        log.error("手动直接回传：{}-{}", orderLog.getId(), dto.getBackMoney());
                        long backMoney = NumberUtil.multiply100(dto.getBackMoney()).longValue();
                        Tuple2<BackStatusEnum, String> backResult = doCallback(orderLog, orderLog.getPayTime(), backMoney);
                        String backMsg = "手动触发回传！";
                        if (StringUtils.isNotBlank(backResult.second)) {
                            backMsg += ("回传失败：" + backResult.second);
                        }
                        update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                                .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
                                .set(GameTencentAppApiOrder::getBackMoney, backMoney)
                                .set(GameTencentAppApiOrder::getBackMsg, backMsg)
                                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
                        );
                    }
                });
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> doCallback(GameTencentAppApiOrder orderLog, LocalDateTime backTime, Long backMoney) {
        GameTencentAppApiUser user = gameTencentAppApiUserService.getOne(new LambdaQueryWrapper<GameTencentAppApiUser>()
                .eq(GameTencentAppApiUser::getGameId, orderLog.getGameId())
                .eq(GameTencentAppApiUser::getUserId, orderLog.getUserId())
                .eq(GameTencentAppApiUser::getAdAccountId, orderLog.getAdAccountId())
                .orderByDesc(GameTencentAppApiUser::getCreateTime)
                .last("limit 1")
        );
        if (user != null) {
            if (user.getCallbackId() == null || user.getCallbackId() < 1) {
                return Tuple2.with(BackStatusEnum.FAILED, "用户匹配不到广告");
            }
        } else  {
            return Tuple2.with(BackStatusEnum.FAILED, "找不到用户");
        }
        GameTencentAppCallback callback = gameTencentAppCallbackService.getById(user.getCallbackId());

        UserActionV3RpcDTO.UserIdRpcDTO userId = UserActionV3RpcDTO.UserIdRpcDTO.builder().build();
        if ("android".equalsIgnoreCase(callback.getDeviceOsType()))  {
            if(StringUtils.isNotBlank(callback.getMuid())) {
                userId.setHashImei(callback.getMuid());
            }
            if(StringUtils.isNotBlank(callback.getHashOaid())) {
                userId.setHashOaid(callback.getHashOaid());
            }
            if(StringUtils.isNotBlank(callback.getHashAndroidId())) {
                userId.setHashAndroidId(callback.getHashAndroidId());
            }
        } else {
            if(StringUtils.isNotBlank(callback.getMuid())) {
                userId.setHashIdfa(callback.getMuid());
            }
        }
        Map<String, Object> actionParams = new HashMap<>();
        actionParams.put("value", backMoney);
        DataReportOfAccountIdV3RpcDTO dataReportOfAccountIdRpcDTO = DataReportOfAccountIdV3RpcDTO.builder()
                .accountId(user.getAdAccountId())
                .userActionSetId(user.getUserActionSetId())
                .action(UserActionV3RpcDTO.builder()
                        .actionTime(backTime)
                        .actionType(ActionTypeEnum.PURCHASE.getActionType())
                        .userId(userId)
                        .trace(UserActionV3RpcDTO.TraceRpcDTO.builder()
                                .clickId(callback.getClickId())
                                .build())
                        .actionParam(actionParams)
                        .build())
                .build();

        GameTencentAppApiBackLog gameTencentBackLog = GameTencentAppApiBackLog.builder()
                .gameId(orderLog.getGameId())
                .userId(orderLog.getUserId())
                .adAccountId(orderLog.getAdAccountId())
                .actionTime(backTime)
                .createTime(LocalDateTime.now())
                .actionType(ActionTypeEnum.PURCHASE.getActionType())
                .orderId(orderLog.getOrderId())
                .imei(orderLog.getImei())
                .oaid(orderLog.getOaid())
                .androidId(orderLog.getAndroidId())
                .idfa(orderLog.getIdfa())
                .caid(orderLog.getCaid())
                .actionParam(actionParams.toString())
                .build();
        ResultVO<Boolean> result = userActionSetRpc.reportByAccountId(dataReportOfAccountIdRpcDTO);
        BackStatusEnum backStatus = BackStatusEnum.FAILED;
        if (result.isSuccess()) {
            backStatus = BackStatusEnum.SUCCESS;
            gameTencentBackLog.setBackLog("回传成功");
        } else {
            gameTencentBackLog.setBackLog(result.getMsg());
        }
        gameTencentAppApiBackLogService.save(gameTencentBackLog);
        return Tuple2.with(backStatus, gameTencentBackLog.getBackLog());
    }

    public static class TencentOrderBackPolicyCheck implements BackPolicyUtil.IBackPolicyCheck {
        private final IGameTencentAppApiOrderService gameTencentAppApiOrderService;
        private final GameBackPolicy gameBackPolicy;
        private final GameTencentAppApiUser userLog;
        private final GameTencentAppApiOrder orderLog;

        public TencentOrderBackPolicyCheck(IGameTencentAppApiOrderService gameTencentAppApiOrderService,
                                           GameBackPolicy gameBackPolicy,
                                           GameTencentAppApiUser userLog,
                                           GameTencentAppApiOrder orderLog) {
            this.gameTencentAppApiOrderService = gameTencentAppApiOrderService;
            this.gameBackPolicy = gameBackPolicy;
            this.userLog = userLog;
            this.orderLog = orderLog;

        }

        @Override
        public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
            numberOfRound = numberOfRound - 1;
            if (backUnit == BackUnitEnum.UNIT_ONCE) {
                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsFirstOrder, firstPolicy)
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                        .last("limit " + numberOfRound)
                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                        .last("limit " + numberOfRound)
                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                        .last("limit " + numberOfRound)
                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                        .last("limit " + numberOfRound)
                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
            } else if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                        .last("limit " + numberOfRound)
                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
            } else {
                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
            }
        }

        @Override
        public long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy) {
            if (backUnit == BackUnitEnum.UNIT_ONCE) {
                if (firstPolicy) {
                    // 首单直接返回 0，必定回传
                    return 0;
                }
                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                        .eq(GameTencentAppApiOrder::getUserId, userId)
                        .eq(GameTencentAppApiOrder::getIsFirstOrder, firstPolicy)
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                );
            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                        .eq(GameTencentAppApiOrder::getUserId, userId)
                        .apply(firstPolicy, "date(register_time) = date(pay_time)")
                        .apply(!firstPolicy, "date(register_time) != date(pay_time)")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                );
            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                        .eq(GameTencentAppApiOrder::getUserId, userId)
                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                );
            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                        .eq(GameTencentAppApiOrder::getUserId, userId)
                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                );
            } else if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                        .eq(GameTencentAppApiOrder::getUserId, userId)
                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                );
            } else {
                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
            }
        }

        @Override
        public long markUpOfFixedRate(int numberOfRound, Long markUpTime) {
            numberOfRound = numberOfRound - 1;
            return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
                    .orderByDesc(GameTencentAppApiOrder::getCreateTime)
                    .last("limit " + numberOfRound)
            ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
        }

        @Override
        public long markUpForUser(String userId, Long markUpTime) {
            return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                    .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
                    .eq(GameTencentAppApiOrder::getUserId, userId)
                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
            );
        }

        @Override
        public Long totalRechargeAmount() {
            Map<String, Object> data = gameTencentAppApiOrderService.getMap(new QueryWrapper<GameTencentAppApiOrder>()
                    .select("ifnull(sum(recharge_money), 0) as recharge_money").lambda()
                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                    .eq(GameTencentAppApiOrder::getUserId, orderLog.getUserId())
                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
            );
            return ObjectUtil.objToLong(data.get("recharge_money"), 0L);
        }
    }
}
