package com.bonus.core.account.v3.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.constant.LeConstants;
import com.bonus.constant.RetCodeEnum;
import com.bonus.core.account.v3.constants.AccStatusEnum;
import com.bonus.core.account.v3.metadata.enums.AccWalletIdEnum;
import com.bonus.core.account.v3.po.AccWalletPayPO;
import com.bonus.core.account.v3.web.vo.AccInfoVO;
import com.bonus.core.account.v3.web.vo.AccOrdBasicsVO;
import com.bonus.core.account.v3.web.vo.AccWalletInfoVO;
import com.bonus.core.common.redis.RedisUtil;
import com.bonus.core.common.utils.TenantContextHolder;
import com.bonus.i18n.I18n;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class AccUtils {
   private static final Logger log = LoggerFactory.getLogger(AccUtils.class);

   private AccUtils() {
   }
   public static String getOperatorName() {
      String operatorName = null;
      try {
         operatorName = SecurityUtils.getUsername();
      } catch (Exception var2) {
         log.error("账户获取当前操作员姓名异常", var2);
      }
      return operatorName;
   }

   public static BigDecimal getWalletBal(List<AccWalletInfoVO> walletInfoList, Integer walletId) {
      return (BigDecimal)walletInfoList.stream().filter((item) -> {
         return item.getWalletId().equals(walletId);
      }).map(AccWalletInfoVO::getWalletBal).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
   }

   public static BigDecimal getWalletFrozenBal(List<AccWalletInfoVO> walletInfoList, Integer walletId) {
      return (BigDecimal)walletInfoList.stream().filter((item) -> {
         return item.getWalletId().equals(walletId);
      }).map(AccWalletInfoVO::getFrozenBalance).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
   }

   public static String getRechargeBatchNum(Integer walletId) {
      AccWalletIdEnum anEnum = AccWalletIdEnum.getEnum(walletId);
      String walletPrefix;
      switch ((AccWalletIdEnum)Objects.requireNonNull(anEnum)) {
         case WALLET:
            walletPrefix = "w";
            break;
         case SUBSIDY:
            walletPrefix = "s";
            break;
         case LUCK_MONEY:
            walletPrefix = "r";
            break;
         default:
            walletPrefix = "n";
      }

      String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
      return walletPrefix + date;
   }

   public static LocalDateTime nowPlusDayTime(Integer days) {
      if (ObjectUtil.isNotNull(days) && days > 0) {
         LocalDate plus = LocalDate.now().plusDays((long)days);
         return plus.atTime(23, 59, 59);
      } else {
         return null;
      }
   }

   public static void checkAccPayUpgradeTask(Long id){
      String lockKey = "yst:merchant-id:user-id:acc:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", String.valueOf(id));
      boolean lock = RedisUtil.tryLock(lockKey, 10, 1800);
      if (!lock) {
         throw new ServiceException("acc_ord_pay_exits_task");
      }
   }
   public static void checkAccWalletBalanceUpdateTask(Long custId){
      String lockKey = "yst:merchant-id:user-id:acc:wallet:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", String.valueOf(custId));
      if (!RedisUtil.tryLock(lockKey, 10, 15)) {
         throw new ServiceException("acc_ord_pay_exits_task");
      }
   }

   public static boolean getAccTradeLockByTradeId(Long tradeId) {
      Long tenantId = TenantContextHolder.getTenantId();
      if (ObjectUtil.isNull(tenantId)) {
         return false;
      } else {
         String lockKey =
                 "yst:merchant-id:user-id:acc:upgrade:lock".replace("merchant-id", tenantId.toString()).replace("user-id", tradeId.toString());
         return RedisUtil.tryLock(lockKey, 0, 600);
      }
//      String lockKey = "yst:merchant-id:user-id:acc:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", tradeId.toString());
//      return RedisUtil.tryLock(lockKey, 0, 600);
   }

   public static void unlockAccWalletBalanceUpdate(Long custId) {
      String lockKey = "yst:merchant-id:user-id:acc:wallet:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", String.valueOf(custId));
      accSafeUnLock(lockKey);
   }

   private static void accSafeUnLock(String lockKey) {
      try {
         RedisUtil.safeUnLock(lockKey);
      } catch (Exception var2) {
         log.error("=====[账户]分布式解锁异常====", var2);
      }
   }

   public static AccOrdBasicsVO transformAccOrdNotEnoughAmount(AccInfoVO accInfoVO, BigDecimal unpaidBalance) {
      AccOrdBasicsVO accOrdBasicsVO = new AccOrdBasicsVO();
      List<AccWalletInfoVO> walletInfoList = accInfoVO.getWalletInfoList();
      accOrdBasicsVO.setAccBal(accInfoVO.getAccAllBal());
      accOrdBasicsVO.setWalletBal(getWalletBal(walletInfoList, AccWalletIdEnum.WALLET.getKey()));
      accOrdBasicsVO.setSubBal(getWalletBal(walletInfoList, AccWalletIdEnum.SUBSIDY.getKey()));
      accOrdBasicsVO.setRedBal(getWalletBal(walletInfoList, AccWalletIdEnum.LUCK_MONEY.getKey()));
      accOrdBasicsVO.setCode(RetCodeEnum.PAY_BALANCE_NO_ENOUGH.getKey());
      accOrdBasicsVO.setUnpaidBalance(unpaidBalance);
      accOrdBasicsVO.setMsg(I18n.getMessage("acc_not_enough_amount", new Object[0]));
      return accOrdBasicsVO;
   }

   public static void accPayUnLockByCustId(Long custId) {
      String lockKey = "yst:merchant-id:user-id:acc:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", String.valueOf(custId));
      accSafeUnLock(lockKey);
   }

   public static AccOrdBasicsVO transformAccOrdTradeDetailV2(AccInfoVO accInfoVO, Long accTradeId, List<AccWalletPayPO> payWalletList) {
      AccOrdBasicsVO accOrdBasicsVO = new AccOrdBasicsVO();
      AccWalletIdEnum[] values = AccWalletIdEnum.values();
      AccWalletIdEnum[] var5 = values;
      int var6 = values.length;

      for(int var7 = 0; var7 < var6; ++var7) {
         AccWalletIdEnum value = var5[var7];
         BigDecimal walletBal = getWalletBal(accInfoVO.getWalletInfoList(), value.getKey());
         BigDecimal payAmount = CollUtil.isEmpty(payWalletList) ? BigDecimal.ZERO : (BigDecimal)payWalletList.stream().filter((item) -> {
            return item.getWalletId().equals(value.getKey());
         }).map(AccWalletPayPO::getAmount).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
         switch (value) {
            case WALLET:
               accOrdBasicsVO.setWalletBal(walletBal);
               accOrdBasicsVO.setWalletPay(payAmount);
               break;
            case SUBSIDY:
               accOrdBasicsVO.setSubBal(walletBal);
               accOrdBasicsVO.setSubsidyPay(payAmount);
               break;
            case LUCK_MONEY:
               accOrdBasicsVO.setRedBal(walletBal);
               accOrdBasicsVO.setRedEnvelopePay(payAmount);
               break;
            default:
                break;
         }
      }

      accOrdBasicsVO.setAccTradeId(accTradeId);
      accOrdBasicsVO.setCode(RetCodeEnum.SUCC.getKey());
      accOrdBasicsVO.setMsg(I18n.getMessage("acc_succ_msg", new Object[0]));
      return accOrdBasicsVO;
   }

   public static AccOrdBasicsVO transformAccOrdTradeDetailV3(Long accTradeId, List<AccWalletInfoVO> walletInfoList, List<AccWalletPayPO> payWalletList) {
      AccOrdBasicsVO accOrdBasicsVO = new AccOrdBasicsVO();
      AccWalletIdEnum[] values = AccWalletIdEnum.values();
      AccWalletIdEnum[] var5 = values;
      int var6 = values.length;

      for(int var7 = 0; var7 < var6; ++var7) {
         AccWalletIdEnum value = var5[var7];
         BigDecimal walletBal = getWalletBal(walletInfoList, value.getKey());
         BigDecimal payAmount = CollUtil.isEmpty(payWalletList) ? BigDecimal.ZERO : (BigDecimal)payWalletList.stream().filter((item) -> {
            return item.getWalletId().equals(value.getKey());
         }).map(AccWalletPayPO::getAmount).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
         switch (value) {
            case WALLET:
               accOrdBasicsVO.setWalletBal(walletBal);
               accOrdBasicsVO.setWalletPay(payAmount);
               break;
            case SUBSIDY:
               accOrdBasicsVO.setSubBal(walletBal);
               accOrdBasicsVO.setSubsidyPay(payAmount);
               break;
            case LUCK_MONEY:
               accOrdBasicsVO.setRedBal(walletBal);
               accOrdBasicsVO.setRedEnvelopePay(payAmount);
               break;
            default:
               break;
         }
      }

      accOrdBasicsVO.setAccTradeId(accTradeId);
      accOrdBasicsVO.setCode(RetCodeEnum.SUCC.getKey());
      accOrdBasicsVO.setMsg(I18n.getMessage("acc_succ_msg", new Object[0]));
      return accOrdBasicsVO;
   }

   public static AccOrdBasicsVO transformAccOrdTradeDetailV4(AccInfoVO accInfoVO, List<AccWalletPayPO> payWalletList) {
      AccOrdBasicsVO accOrdBasicsVO = new AccOrdBasicsVO();
      AccWalletIdEnum[] values = AccWalletIdEnum.values();
      AccWalletIdEnum[] var4 = values;
      int var5 = values.length;

      for(int var6 = 0; var6 < var5; ++var6) {
         AccWalletIdEnum value = var4[var6];
         BigDecimal walletBal = getWalletBal(accInfoVO.getWalletInfoList(), value.getKey());
         BigDecimal payAmount = CollUtil.isEmpty(payWalletList) ? BigDecimal.ZERO : (BigDecimal)payWalletList.stream().filter((item) -> {
            return item.getWalletId().equals(value.getKey());
         }).map(AccWalletPayPO::getAmount).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
         BigDecimal subtract = walletBal.subtract(payAmount);
         switch (value) {
            case WALLET:
               accOrdBasicsVO.setWalletBal(subtract);
               accOrdBasicsVO.setWalletPay(payAmount);
               break;
            case SUBSIDY:
               accOrdBasicsVO.setSubBal(subtract);
               accOrdBasicsVO.setSubsidyPay(payAmount);
               break;
            case LUCK_MONEY:
               accOrdBasicsVO.setRedBal(subtract);
               accOrdBasicsVO.setRedEnvelopePay(payAmount);
               break;
            default:
               break;
         }
      }

      accOrdBasicsVO.setCode(RetCodeEnum.SUCC.getKey());
      accOrdBasicsVO.setMsg(I18n.getMessage("acc_succ_msg", new Object[0]));
      log.info("账户钱包减去支付金额,组装结果:{}", JSONUtil.toJsonStr(accOrdBasicsVO));
      return accOrdBasicsVO;
   }

   public static void accTradeUnLockByTradeId(Long tradeId) {
      String lockKey = "yst:merchant-id:user-id:acc:upgrade:lock".replace("merchant-id", TenantContextHolder.getTenantId().toString()).replace("user-id", tradeId.toString());
      accSafeUnLock(lockKey);
   }

}
