package com.bonus.core.order.utils;

import cn.hutool.core.collection.CollUtil;
import com.bonus.constant.LeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class LeNumUtil {
   private static final Logger log = LoggerFactory.getLogger(LeNumUtil.class);
   private static final long EPOCH = LocalDateTime.of(2021, 12, 29, 9, 2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
//   @Autowired
//   @Lazy
//   private OrderInfoService orderInfoService;
//   @Autowired
//   @Lazy
//   private RedisTemplate<Object, Object> redisTemplate;
//   @Value("${system.order.call.max-num:}")
//   private Long callMaxNum;

//   public static String getCanteenNum(String superNum, String latestNum, boolean differentFlag) {
//      if (CharSequenceUtil.isBlank(latestNum)) {
//         latestNum = "01";
//      } else {
//         if (latestNum.contains("-")) {
//            latestNum = latestNum.substring(latestNum.lastIndexOf("-") + 1);
//         } else {
//            if (latestNum.length() < 2) {
//               latestNum = "0" + latestNum;
//            }
//
//            latestNum = latestNum.substring(latestNum.length() - 2);
//         }
//
//         latestNum = String.valueOf(Integer.valueOf(latestNum) + 1);
//         if (latestNum.length() % 2 == 1) {
//            latestNum = "0" + latestNum;
//         }
//      }
//
//      return differentFlag ? superNum + "-" + latestNum : superNum + latestNum;
//   }
//
//   public String getMealCode(String prefix, Long canteenId, Long stallId, LocalDate orderDate, Integer mealtimeType) {
//      if (!isValidId(canteenId) && !isValidId(stallId)) {
//         return "";
//      } else if (LocalDate.now().isAfter(orderDate)) {
//         return "";
//      } else {
//         String callNumPrefix = CharSequenceUtil.isNotBlank(prefix) ? prefix : "";
//         Long merchantId = TenantContextHolder.getTenantId();
//         String dateStr = orderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//         String shopIdStr = isValidId(stallId) ? String.valueOf(stallId) : String.valueOf(canteenId);
//         String mealtimeStr = isValidId(mealtimeType) ? String.valueOf(mealtimeType) : "-1";
//         String redisKey = CharSequenceUtil.format("yst:{}:meal-code:{}:{}:{}:{}", new Object[]{merchantId, shopIdStr, dateStr, mealtimeStr, callNumPrefix});
//         log.info("叫号缓存key：{}", redisKey);
//         BoundValueOperations<Object, Object> valueOperations = this.redisTemplate.boundValueOps(redisKey);
//         Object s = valueOperations.get();
//         if (ObjectUtil.isNull(s)) {
//            String maxMealCodeOfDate = this.orderInfoService.getMaxMealCodeOfDate(orderDate, mealtimeType, canteenId, stallId);
//            log.info("当前最大叫号：{}", maxMealCodeOfDate);
//            maxMealCodeOfDate = CharSequenceUtil.removePrefix(maxMealCodeOfDate, callNumPrefix);
//            int currentNum = NumberUtil.isNumber(maxMealCodeOfDate) ? NumberUtil.parseInt(maxMealCodeOfDate) : 0;
//            Duration expireDuration = LocalDateTimeUtil.between(LocalDateTimeUtil.now(), LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.now()));
//            valueOperations.setIfAbsent(currentNum, expireDuration);
//         }
//
//         Long increment = valueOperations.increment(1L);
//         if (this.callMaxNum != null && increment != null && increment > this.callMaxNum) {
//            increment = increment % this.callMaxNum;
//         }
//
//         String format = String.format("%03d", increment);
//         log.info("叫的多少号{}", callNumPrefix + format);
//         return callNumPrefix + format;
//      }
//   }

   public static boolean isValidId(Long id) {
      return id != null && id != -1L && id != 0L;
   }

   public static boolean isValidId(Integer id) {
      return id != null && id != -1 && id != 0;
   }

   public static long timestampOfId(Long id) {
      return (id >> 22) + EPOCH;
   }

   public static Long idOrDefault(Long id) {
      return isValidId(id) ? id : LeConstants.DATA_DEFAULT_LONG;
   }
//
//   public static <T, R> List<R> toFieldList(Collection<T> dataList, Function<T, R> func) {
//      return (List)(CollUtil.isEmpty(dataList) ? CollUtil.newArrayList(new Object[0]) : (List)dataList.stream().map(func).distinct().collect(Collectors.toList()));
//   }
//
//   public static <T, R> R reduceField(Collection<T> dataList, Function<T, R> func, R defaultValue) {
//      if (CollUtil.isEmpty(dataList)) {
//         return defaultValue;
//      } else {
//         Set<R> fieldSet = (Set)dataList.stream().map(func).collect(Collectors.toSet());
//         return fieldSet.size() == 1 ? CollUtil.getFirst(fieldSet) : defaultValue;
//      }
//   }

   public static <T> BigDecimal sumField(Collection<T> dataList, Function<T, BigDecimal> func) {
      return CollUtil.isEmpty(dataList) ? BigDecimal.ZERO : (BigDecimal)dataList.stream().map(func).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
   }

   public static <T> int sumFieldInt(Collection<T> dataList, Function<T, Integer> func) {
      return CollUtil.isEmpty(dataList) ? 0 : (Integer)dataList.stream().map(func).filter(Objects::nonNull).reduce(0, Integer::sum);
   }

   public static <T, R> R reduceField(Collection<T> dataList, Function<T, R> func, R defaultValue) {
      if (CollUtil.isEmpty(dataList)) {
         return defaultValue;
      } else {
         Set<R> fieldSet = (Set)dataList.stream().map(func).collect(Collectors.toSet());
         return fieldSet.size() == 1 ? CollUtil.getFirst(fieldSet) : defaultValue;
      }
   }

   public static <T> void calcShareAmount(List<T> dataList, BigDecimal totalAmount, Function<T, BigDecimal> amountField, BiConsumer<T, BigDecimal> saveFunc) {
      List<T> dataListSorted = (List)dataList.stream().sorted(Comparator.comparing(amountField)).collect(Collectors.toList());
      BigDecimal totalNeedPayRealAmount = (BigDecimal)dataListSorted.stream().map(amountField).reduce(BigDecimal.ZERO, BigDecimal::add);
      BigDecimal calcRealAmount = BigDecimal.ZERO;

      for(int i = 0; i < dataListSorted.size(); ++i) {
         T data = dataListSorted.get(i);
         BigDecimal realAmount;
         if (i >= dataListSorted.size() - 1) {
            realAmount = totalAmount.subtract(calcRealAmount);
         } else if (totalNeedPayRealAmount.compareTo(BigDecimal.ZERO) == 0) {
            realAmount = BigDecimal.ZERO;
         } else {
            realAmount = ((BigDecimal)amountField.apply(data)).multiply(totalAmount).divide(totalNeedPayRealAmount, 0, RoundingMode.HALF_UP);
            calcRealAmount = calcRealAmount.add(realAmount);
         }

         saveFunc.accept(data, realAmount);
      }

   }

//
//   public static <T> BigDecimal sumField(Collection<T> dataList, Predicate<T> filter, Function<T, BigDecimal> func) {
//      return CollUtil.isEmpty(dataList) ? BigDecimal.ZERO : (BigDecimal)dataList.stream().filter(filter).map(func).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
//   }
//
//   public static <T> void calcShareAmount(List<T> dataList, BigDecimal totalAmount, Function<T, BigDecimal> amountField, BiConsumer<T, BigDecimal> saveFunc) {
//      List<T> dataListSorted = (List)dataList.stream().sorted(Comparator.comparing(amountField)).collect(Collectors.toList());
//      BigDecimal totalNeedPayRealAmount = (BigDecimal)dataListSorted.stream().map(amountField).reduce(BigDecimal.ZERO, BigDecimal::add);
//      BigDecimal calcRealAmount = BigDecimal.ZERO;
//
//      for(int i = 0; i < dataListSorted.size(); ++i) {
//         T data = dataListSorted.get(i);
//         BigDecimal realAmount;
//         if (i >= dataListSorted.size() - 1) {
//            realAmount = totalAmount.subtract(calcRealAmount);
//         } else if (totalNeedPayRealAmount.compareTo(BigDecimal.ZERO) == 0) {
//            realAmount = BigDecimal.ZERO;
//         } else {
//            realAmount = ((BigDecimal)amountField.apply(data)).multiply(totalAmount).divide(totalNeedPayRealAmount, 0, RoundingMode.HALF_UP);
//            calcRealAmount = calcRealAmount.add(realAmount);
//         }
//
//         saveFunc.accept(data, realAmount);
//      }
//
//   }
}
