package com.zanxiang.game.back.serve.utils;

import com.github.sd4324530.jtuple.Tuple2;
import com.github.sd4324530.jtuple.Tuple3;
import com.github.sd4324530.jtuple.Tuples;
import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
import com.zanxiang.game.back.serve.pojo.vo.GameBackPolicyVO;
import com.zanxiang.module.util.DateUtil;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

@Slf4j
public class BackPolicyUtil {
    private static final long[] RECHARGE_LEVEL = {12 * 100L, 30 * 100L, 50 * 100L, 98 * 100L, 198 * 100L, 328 * 100L, 649 * 100L, 998 * 100L, 2998 * 100L};

    static {
        Arrays.sort(RECHARGE_LEVEL);
    }

    /**
     * 订单回传
     *
     * @return <是否回传，回传金额，回传描述>
     */
    public static Tuple3<Boolean, Long, String> backOrder(String orderId, GameBackPolicy gameBackPolicy,
                                                          long rechargeMoney, boolean isFirstOrder,
                                                          LocalDateTime payTime, LocalDateTime regTime,
                                                          String userId, IBackPolicyCheck backPolicyCheck) {
        if (null == gameBackPolicy) {
            log.error("订单 id[{}]找不到回传策略，默认回传", orderId);
            return Tuples.tuple(Boolean.TRUE, rechargeMoney, "没有回传策略");
        }
        if (gameBackPolicy.getSupperSmallAmount() != null && gameBackPolicy.getSupperSmallAmount() >= rechargeMoney) {
            log.error("订单 id[{}]被判定为超小额订单({})，默认不回传", orderId, gameBackPolicy.getSupperSmallAmount());
            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "超小额订单(<=" + gameBackPolicy.getSupperSmallAmount() + ")，不回传");
        }
        BackUnitEnum backUnit = gameBackPolicy.getBackUnit() == null ? BackUnitEnum.UNIT_ONCE : BackUnitEnum.getByValue(gameBackPolicy.getBackUnit());
        Long totalRechargeAmount = null;
        if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
            Long totalAmount = backPolicyCheck.totalRechargeAmount();
            totalRechargeAmount = totalAmount == null ? rechargeMoney : totalAmount + rechargeMoney;
        }

        Boolean firstPolicy = null;
        Long markUpTime = null;
        Integer backType;
        String backRate;
        if (gameBackPolicy.getRegPayIntervalTime() != null
                && ((DateUtil.localDateTimeToSecond(payTime) - DateUtil.localDateTimeToSecond(regTime)) / 60) > gameBackPolicy.getRegPayIntervalTime()) {
            // 补单
            log.error("订单 id[{}]通过回传策略[{}]判断后，超过注册充值间隔时间，走补单逻辑 {}, money: {}.", orderId, gameBackPolicy.getId(), gameBackPolicy.getRegPayIntervalTime(), totalRechargeAmount);
            if (gameBackPolicy.getMarkUpOrder() != null && gameBackPolicy.getMarkUpOrder()) {
                long money = backUnit == BackUnitEnum.LARGE_AMOUNT ? totalRechargeAmount : rechargeMoney;
                markUpTime = gameBackPolicy.getRegPayIntervalTime();
                if (money <= gameBackPolicy.getMarkUpOrderMinMoney()) {
                    // 小额
                    backType = gameBackPolicy.getMarkUpOrderMinMoneyType();
                    backRate = gameBackPolicy.getMarkUpOrderMinMoneyRate();
                } else if (money >= gameBackPolicy.getMarkUpOrderMaxMoney()) {
                    // 大额
                    backType = gameBackPolicy.getMarkUpOrderMaxMoneyType();
                    backRate = gameBackPolicy.getMarkUpOrderMaxMoneyRate();
                } else {
                    backType = gameBackPolicy.getMarkUpOrderOtherMoneyType();
                    backRate = gameBackPolicy.getMarkUpOrderOtherMoneyRate();
                }
                String backMsg = "";
                if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
                    // 固定比例回传
                    String[] temp = backRate.split(":");
                    int backCount = Integer.parseInt(temp[0]);
                    int ignoreCount = Integer.parseInt(temp[1]);
                    if (backCount == 0) {
                        log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：回传比例 {}", orderId, gameBackPolicy.getId(), backRate);
                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-按比例回传，回传比例为 0，全部不回传");
                    }
                    if (ignoreCount == 0) {
                        log.error("订单 id[{}]通过回传策略[{}]判断后，回传，原因：回传比例 {}", orderId, gameBackPolicy.getId(), backRate);
                        return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-按比例回传，忽略比例为 0，全部回传");
                    }
                    long isBackCount = backPolicyCheck.markUpOfFixedRate(backCount + ignoreCount, markUpTime);
                    backMsg = "补单-按比例回传，每 " + (backCount + ignoreCount) + "笔回传 " + backCount + "笔，当前第 " + (isBackCount + 1) + "笔";
                    if (isBackCount >= backCount) {
                        log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
                    }
                } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
                    // 随机概率回传
                    boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(backRate)).intValue();
                    backMsg = "补单-随机概率回传(" + NumberUtil.multiply100(new BigDecimal(backRate)) + "%)";
                    if (!isBack) {
                        log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
                    }
                } else {
                    throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误，未知的回传类型：" + backType);
                }
                if (gameBackPolicy.getMarkUpBackCountOfUser() == null) {
                    log.error("订单 id[{}]通过回传策略[{}]判断后，回传，原因：回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
                    return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
                }
                long userBackCount = backPolicyCheck.markUpForUser(userId, markUpTime);
                backMsg = backMsg + "，单用户最大回传 " + gameBackPolicy.getMarkUpBackCountOfUser() + "笔，当前已回传 " + userBackCount + "笔";
                log.error("订单 id[{}]通过回传策略[{}]判断后，是否回传：{}，原因：{}", orderId, gameBackPolicy.getId(), userBackCount < gameBackPolicy.getMarkUpBackCountOfUser(), backMsg);
                return Tuples.tuple(userBackCount < gameBackPolicy.getMarkUpBackCountOfUser(), downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
            } else {
                log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：超过注册充值间隔时间但是未开启补单", orderId, gameBackPolicy.getId());
                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-未开启补单");
            }
        }

        // 正常判断
        if (backUnit == BackUnitEnum.UNIT_ONCE) {
            firstPolicy = isFirstOrder;
        } else if (backUnit == BackUnitEnum.UNIT_DAY) {
            long intervalDays = DateUtil.intervalOfDays(regTime.toLocalDate(), payTime.toLocalDate());
            firstPolicy = intervalDays == 0;
        } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
            long intervalHours = DateUtil.intervalOfHour(regTime, payTime);
            firstPolicy = intervalHours < 24;
        } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
            long intervalHours = DateUtil.intervalOfHour(regTime, payTime);
            firstPolicy = intervalHours < 48;
        } else if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
            // 是否是小额订单
            firstPolicy = rechargeMoney < gameBackPolicy.getLargeAmount();
        } else {
            throw new RuntimeException("未知的回传单位：" + backUnit);
        }
        if (firstPolicy) {
            long money = backUnit == BackUnitEnum.LARGE_AMOUNT ? totalRechargeAmount : rechargeMoney;
            if (money <= gameBackPolicy.getFirstMinMoney()) {
                // 小额
                backType = gameBackPolicy.getFirstMinMoneyType();
                backRate = gameBackPolicy.getFirstMinMoneyRate();
            } else if (money >= gameBackPolicy.getFirstMaxMoney()) {
                // 大额
                backType = gameBackPolicy.getFirstMaxMoneyType();
                backRate = gameBackPolicy.getFirstMaxMoneyRate();
            } else {
                backType = gameBackPolicy.getFirstOtherMoneyType();
                backRate = gameBackPolicy.getFirstOtherMoneyRate();
            }
            log.error("订单 id[{}]通过回传策略[{}]判断后走首日逻辑：backType: {}, backRate: {}, money: {}", orderId, gameBackPolicy.getId(), backType, backRate, money);
        } else {
            long money = backUnit == BackUnitEnum.LARGE_AMOUNT ? totalRechargeAmount : rechargeMoney;
            if (money <= gameBackPolicy.getRechargeMinMoney()) {
                // 小额
                backType = gameBackPolicy.getRechargeMinMoneyType();
                backRate = gameBackPolicy.getRechargeMinMoneyRate();
            } else if (money >= gameBackPolicy.getRechargeMaxMoney()) {
                // 大额
                backType = gameBackPolicy.getRechargeMaxMoneyType();
                backRate = gameBackPolicy.getRechargeMaxMoneyRate();
            } else {
                backType = gameBackPolicy.getRechargeOtherMoneyType();
                backRate = gameBackPolicy.getRechargeOtherMoneyRate();
            }
            log.error("订单 id[{}]通过回传策略[{}]判断后走次日逻辑, backType: {}, backRate: {}, money: {}", orderId, gameBackPolicy.getId(), backType, backRate, money);
        }
        Integer maxBackCountOfUser = firstPolicy ? gameBackPolicy.getFirstBackCountOfUser() : gameBackPolicy.getRechargeBackCountOfUser();
        String backMsg = firstPolicy ? "首-" : "次-";
        String downLevelString = firstPolicy ? gameBackPolicy.getFirstDownLevel() : gameBackPolicy.getRechargeDownLevel();
        if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
            // 固定比例回传
            String[] temp = backRate.split(":");
            int backCount = Integer.parseInt(temp[0]);
            int ignoreCount = Integer.parseInt(temp[1]);
            if (backCount == 0) {
                backMsg = backMsg + "按比例回传，回传比例为 0，全部不回传";
                log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
            }
            if (ignoreCount == 0) {
                backMsg = backMsg + "按比例回传，忽略比例为 0，全部回传";
                log.error("订单 id[{}]通过回传策略[{}]判断后，回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), backMsg);
            }
            long isBackCount = backPolicyCheck.backCountForFixedRate(backCount + ignoreCount, backUnit, firstPolicy);
            backMsg = backMsg + "按比例回传，每 " + (backCount + ignoreCount) + "笔回传 " + backCount + "笔，当前第 " + (isBackCount + 1) + "笔";
            if (isBackCount >= backCount) {
                log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
            }
        } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
            // 随机概率回传
            boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(backRate)).intValue();
            backMsg = backMsg + "随机概率回传(" + NumberUtil.multiply100(new BigDecimal(backRate)) + "%)";
            if (!isBack) {
                log.error("订单 id[{}]通过回传策略[{}]判断后，不回传，原因：{}", orderId, gameBackPolicy.getId(), backMsg);
                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
            }
        } else {
            throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误，未知的回传类型：" + backType);
        }

        if (maxBackCountOfUser == null) {
            log.error("订单 id[{}]通过回传策略[{}]判断后，回传，原因：回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
            return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), backMsg);
        }
        long userBackCount = backPolicyCheck.backCountForUser(backUnit, userId, firstPolicy);
        backMsg = backMsg + "，单用户最大回传 " + maxBackCountOfUser + "笔，当前已回传 " + userBackCount + "笔";
        log.error("订单 id[{}]通过回传策略[{}]判断后，是否回传：{}，原因：{}", orderId, gameBackPolicy.getId(), userBackCount < maxBackCountOfUser, backMsg);
        return Tuples.tuple(userBackCount < maxBackCountOfUser, downLevel(rechargeMoney, downLevelString), backMsg);
    }

    private static Long downLevel(Long rechargeMoney, String downLevelStr) {
        if (StringUtils.isBlank(downLevelStr)) {
            return rechargeMoney;
        }
        String[] downLevelList = downLevelStr.split(",");
        for (String downLevel : downLevelList) {
            String[] tmp = downLevel.split("_");
            long minMoney = Long.parseLong(tmp[0]);
            long maxMoney = Long.parseLong(tmp[1]);
            Long backMoney = Long.parseLong(tmp[2]);
            if (rechargeMoney >= minMoney && rechargeMoney <= maxMoney) {
                return backMoney;
            }
        }
        return rechargeMoney;
    }

    private static Tuple2<Integer, Integer> approximate(int molecular, int denominator) {
        if (molecular % denominator == 0) {
            int temp = molecular / denominator;
            return Tuples.tuple(temp, temp);
        }
        int model = 2;
        do {
            if (molecular % model == 0 && denominator % model == 0) {
                molecular = molecular / model;
                denominator = denominator / model;
                continue;
            }
            model++;
        } while (model <= denominator / 2);
        return Tuples.tuple(molecular, denominator);
    }

    /**
     * 降档
     */
    public static long lowRechargeLevel(long rechargeMoney, String levelDownStr) {
        if (StringUtils.isBlank(levelDownStr)) {
            // 无需降档
            return rechargeMoney;
        }
        String[] levelDownStrList = levelDownStr.split(",");
        for (String levelDown : levelDownStrList) {
            String[] tmp = levelDown.split("_");
            long min = Long.parseLong(tmp[0]), max = Long.parseLong(tmp[1]), back = Long.parseLong(tmp[2]);
            if (rechargeMoney >= min && rechargeMoney <= max) {
                return back;
            }
        }
        // 没有匹配金额规则，直接返回
        return rechargeMoney;
    }

    public interface IBackPolicyCheck {
        /**
         * 按比例回传时单次循环已经回传的人数
         */
        long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy);

        /**
         * 单个用户已回传订单数
         */
        long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy);

        /**
         * 补单，按比例回传时单次循环已经回传的人数
         */
        long markUpOfFixedRate(int numberOfRound, Long markUpTime);

        /**
         * 补单，单个用户已回传订单数
         */
        long markUpForUser(String userId, Long markUpTime);

        /**
         * 获取用户的累充金额
         */
        Long totalRechargeAmount();
    }
}
