package com.red.circle.other.infra.database.mongo.service.team;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.red.circle.other.infra.database.mongo.dto.team.TeamBillMemberTarget;
import com.red.circle.other.infra.database.mongo.dto.team.TeamBillPolicyType;
import com.red.circle.other.infra.database.mongo.dto.team.TeamPolicy;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyManager;
import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig;
import com.red.circle.other.infra.database.rds.entity.team.BillDiamondBalance;
import com.red.circle.other.inner.enums.team.TeamMemberTargetIndex;
import com.red.circle.other.inner.enums.team.TeamMemberTargetStatus;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.num.NumUtils;
import com.red.circle.tool.core.text.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author pengliang on 2022/12/16
 */
public final class TeamBillCycleUtils {

  private static final Logger log = LoggerFactory.getLogger(TeamBillCycleUtils.class);

  /**
   * Policy Map Key 分隔符.
   */
  public static final String POLICY_KEY_DELIMITER = "_";

  /**
   * 默认国家代码（通用政策）.
   */
  public static final String DEFAULT_COUNTRY_CODE = "DEFAULT";

  /**
   * 构建 policy map 的 key.
   *
   * @param region      区域
   * @param countryCode 国家代码
   * @return map key，格式：region_countryCode 或 region_DEFAULT
   */
  public static String buildPolicyMapKey(String region, String countryCode) {
    return region + POLICY_KEY_DELIMITER +
        (StringUtils.isNotBlank(countryCode) ? countryCode : DEFAULT_COUNTRY_CODE);
  }

  /**
   * 从 policy map 中获取匹配的政策（支持 fallback）.
   *
   * @param policyMap   政策 Map
   * @param region      区域
   * @param countryCode 国家代码
   * @return 匹配的政策，优先返回精确匹配的，没有则返回通用政策（countryCode=null）
   */
  public static TeamPolicyManager getPolicyFromMap(
      Map<String, TeamPolicyManager> policyMap,
      String region,
      String countryCode) {

    if (policyMap == null || region == null) {
      return null;
    }

    // 1. 先找精确匹配 countryCode 的政策
    String key = buildPolicyMapKey(region, countryCode);
    TeamPolicyManager policy = policyMap.get(key);

    // 2. Fallback：如果没找到，查找通用政策（countryCode = null）
    if (policy == null) {
      key = buildPolicyMapKey(region, null);
      policy = policyMap.get(key);
    }

    return policy;
  }

  /**
   * 团队周期数.
   */
  public static Long calculatorBillCycle(Long billCycle) {
    return Objects.isNull(billCycle) || billCycle <= 0 ? 1 : billCycle;
  }

  /**
   * 账单开始时间.
   */
  public static Integer nowStartDateNumber() {
    return ZonedDateTimeAsiaRiyadhUtils.nowDateToInt();
  }

  /**
   * 计算出账时间-沙特时区跟目标计算统一.
   * <p>
   * 创建账单（billType=WEEK）： 创建日期 2022-12-15， 周日18
   * <p>
   * 出账日（billType=WEEK,billCycle=1）：2022-12-15 ~ 2022-12-18
   * <p>
   * 出账日（billType=WEEK,billCycle=2）：2022-12-15 ~ 2022-12-25
   * <p>
   * 依次类推
   */
  @Deprecated
  public static Integer nowOutDateNumber(TeamBillPolicyType billType, Long billCycle) {
    Long plusBillCycle = calculatorBillCycle(billCycle);
    if (Objects.equals(billType, TeamBillPolicyType.MONTH)) {
      return ZonedDateTimeAsiaRiyadhUtils.getLastDayOfMonthToInt(
          ZonedDateTimeAsiaRiyadhUtils.now().plusMonths(plusBillCycle - 1));
    }

    if (Objects.equals(billType, TeamBillPolicyType.WEEK)) {
      return ZonedDateTimeAsiaRiyadhUtils.getWeekSunday(
          ZonedDateTimeAsiaRiyadhUtils.now().plusWeeks(plusBillCycle - 1));
    }
    throw new IllegalArgumentException("billType notRange.");
  }

  /**
   * 账单开始时间.
   * <p>
   * 月：下个月第一天
   * <p>
   * 周：下周第一天
   */
  @Deprecated
  public static Integer nextStartDateNumber(TeamBillPolicyType billType, Long billCycle) {
    Long plusBillCycle = calculatorBillCycle(billCycle);
    if (Objects.equals(billType, TeamBillPolicyType.MONTH)) {
      return ZonedDateTimeAsiaRiyadhUtils.getFirstDayOfMonthToInt(
          ZonedDateTimeAsiaRiyadhUtils.now().plusMonths(plusBillCycle));
    }
    if (Objects.equals(billType, TeamBillPolicyType.WEEK)) {
      return ZonedDateTimeAsiaRiyadhUtils.getWeekMonday(
          ZonedDateTimeAsiaRiyadhUtils.now().plusWeeks(plusBillCycle));
    }
    throw new IllegalArgumentException("billType notRange.");
  }

  /**
   * 计算出账时间-沙特时区跟目标计算统一.
   * <p>
   * 创建账单（billType=WEEK）： 创建日期 2022-12-15， 周日18
   * <p>
   * 出账日（billType=WEEK,billCycle=1）：2022-12-19 ~ 2022-12-25
   * <p>
   * 出账日（billType=WEEK,billCycle=2）：2022-12-26 ~ 2023-01-01
   * <p>
   * 依次类推
   */
  @Deprecated
  public static Integer nextOutDateNumber(TeamBillPolicyType billType, Long billCycle) {
    Long plusBillCycle = calculatorBillCycle(billCycle);
    if (Objects.equals(billType, TeamBillPolicyType.MONTH)) {
      return ZonedDateTimeAsiaRiyadhUtils.getLastDayOfMonthToInt(
          ZonedDateTimeAsiaRiyadhUtils.now().plusMonths(plusBillCycle * 2 - 1)
      );
    }

    if (Objects.equals(billType, TeamBillPolicyType.WEEK)) {
      return ZonedDateTimeAsiaRiyadhUtils.getWeekSunday(
          ZonedDateTimeAsiaRiyadhUtils.now().plusWeeks(plusBillCycle * 2 - 1)
      );
    }
    throw new IllegalArgumentException("billType notRange.");
  }

  /**
   * 计算成员工作情况.
   */
  public static TeamBillMemberTarget calculatorPolicyTarget(TeamMemberTarget target,
      TeamPolicyManager policy) {

    if (Objects.isNull(target)) {
      throw new IllegalArgumentException("target is null.");
    }
    return calculatorPolicyTarget(List.of(target), policy).get(0);
  }

  /**
   * 计算有效天数
   * 规则：每日在线时长 >= 120分钟算作有效一天
   *
   * @param target 成员目标数据
   * @return 有效天数
   */
  public static Integer calculateEffectiveDay(TeamMemberTarget target) {
    if (target == null || target.getDailyTargets() == null) {
      return 0;
    }

    // 统计每日在线时长 >= 120分钟的天数
    int effectiveDayCount = 0;
    for (Object dailyData : target.getDailyTargets()) {
      // 假设dailyData是包含ownOnlineTime和otherOnlineTime的对象
      Long dailyOnlineTime = getDailyTotalOnlineTime(dailyData);
      if (dailyOnlineTime != null && dailyOnlineTime >= 120) {
        effectiveDayCount++;
      }
    }

    return effectiveDayCount;
  }

  /**
   * 获取每日总在线时长
   * 根据您的MongoDB数据结构，需要累加ownOnlineTime和otherOnlineTime
   */
  private static Long getDailyTotalOnlineTime(Object dailyData) {
    try {
      JSONObject jsonObject = (JSONObject) JSON.toJSON(dailyData);
      Long ownOnlineTime = NumUtils.isNullDefaultZero(jsonObject.getLong("ownOnlineTime"));
      Long otherOnlineTime = NumUtils.isNullDefaultZero(jsonObject.getLong("otherOnlineTime"));
      return ownOnlineTime + otherOnlineTime;
    } catch (Exception e) {
      return 0L;
    }
  }

  /**
   * 计算成员工作情况.
   */
  public static List<TeamBillMemberTarget> calculatorPolicyTarget(List<TeamMemberTarget> targets,
      TeamPolicyManager policy) {

    if (CollectionUtils.isEmpty(targets)) {
      return Lists.newArrayList();
    }

    List<TeamPolicy> teamPolicies = Objects.nonNull(policy)
        ? policy.getPolicy().stream()
        .sorted(Comparator.comparing(TeamPolicy::getLevel, Comparator.reverseOrder()))
        .collect(Collectors.toList())
        : Lists.newArrayList();

      // 计算上月溢出值并应用到当前月
      Map<Long, Long> userOverflowMap = calculateLastMonthOverflow(targets, teamPolicies);
      applyOverflowToCurrentMonth(targets, userOverflowMap);

    return targets.stream()
            .filter(target -> !Boolean.TRUE.equals(target.getHistory()))
            .map(target -> {
      long targetTimeHours = target.sumAllTargetTime() / 60;
      Long acceptGiftValue = target.sumAcceptGiftValue();
      Integer effectiveDay = calculateEffectiveDay(target);

      TeamBillMemberTarget resultTarget = new TeamBillMemberTarget()
          .setTargetId(target.getTimeId())
          .setSysOrigin(target.getSysOrigin())
          .setUserId(target.getUserId())
          .setAcceptGiftValue(target.sumAcceptGiftValue())
          .setGiveGiftValue(target.sumGiveGiftValue())
          .setRoomValue(target.sumRoomValue())
          .setOnlineTime(target.sumAllTargetTime())
          .setMemberSalary(BigDecimal.ZERO)
          .setOwnSalary(BigDecimal.ZERO)
          .setTotalSalary(BigDecimal.ZERO)
          .setSatisfyLevel(Boolean.FALSE);

      for (TeamPolicy teamPolicy : teamPolicies) {
        Long policyOnlineTimeHours = NumUtils.isNullDefaultZero(teamPolicy.getOnlineTime());
        Long policyGiftValue = NumUtils.isNullDefaultZero(teamPolicy.getTarget());

        // 礼物流水不满足条件
        if (acceptGiftValue < policyGiftValue) {
          continue;
        }

          Integer policyEffectiveDay = NumUtils.isNullDefaultZero(teamPolicy.getEffectiveDay());
          resultTarget.setLevel(teamPolicy.getLevel());
          resultTarget.setSatisfyLevel(Boolean.TRUE);

          if (targetTimeHours >= policyOnlineTimeHours && effectiveDay >= policyEffectiveDay) {
              resultTarget.setMemberSalary(teamPolicy.getMemberSalary());
              resultTarget.setOwnSalary(teamPolicy.getOwnSalary());
              resultTarget.setTotalSalary(teamPolicy.getTotalSalary());
              return resultTarget;
          } else {
              resultTarget.setMemberSalary(teamPolicy.getMemberSalary().multiply(new BigDecimal("0.9")).setScale(2, RoundingMode.DOWN));
              resultTarget.setTotalSalary(teamPolicy.getMemberSalary().multiply(new BigDecimal("0.9")).setScale(2, RoundingMode.DOWN));
          }

          resultTarget.setPropsRewards(teamPolicy.getPropsRewards());
          return resultTarget;
      }
      return resultTarget;
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  /**
   * 计算成员工作情况（Map版本 - 支持多region和countryCode）.
   *
   * @param targets   目标列表，每个target包含region和countryCode
   * @param policyMap 政策Map，key格式：region_countryCode
   * @return 计算结果列表
   */
  public static List<TeamBillMemberTarget> calculatorPolicyTargetWithMap(
      List<TeamMemberTarget> targets,
      Map<String, TeamPolicyManager> policyMap) {

    if (CollectionUtils.isEmpty(targets)) {
      return Lists.newArrayList();
    }

    // 按 region + countryCode 分组
    Map<String, List<TeamMemberTarget>> groupedTargets = targets.stream()
        .filter(target -> !Boolean.TRUE.equals(target.getHistory()))
        .collect(Collectors.groupingBy(target ->
            buildPolicyMapKey(target.getRegion(), target.getCountryCode())));

    List<TeamBillMemberTarget> allResults = new ArrayList<>();

    // 对每组使用对应的 policy 计算
    groupedTargets.forEach((policyKey, groupTargets) -> {
      // 取第一个 target 只是为了获取 region 和 countryCode（同一组的都相同）
      TeamMemberTarget firstTarget = groupTargets.get(0);
      // 从 map 中获取对应的 policy（自动 fallback）
      TeamPolicyManager policy = getPolicyFromMap(
          policyMap,
          firstTarget.getRegion(),
          firstTarget.getCountryCode());

      if (policy != null) {
        // 使用原有的单 policy 计算逻辑，传入整个 groupTargets 列表
        List<TeamBillMemberTarget> results = calculatorPolicyTarget(groupTargets, policy);
        allResults.addAll(results);
      } else {
        // 没有匹配的政策，返回默认值
        groupTargets.forEach(target -> {
          TeamBillMemberTarget defaultTarget = new TeamBillMemberTarget()
              .setTargetId(target.getTimeId())
              .setSysOrigin(target.getSysOrigin())
              .setUserId(target.getUserId())
              .setAcceptGiftValue(target.sumAcceptGiftValue())
              .setGiveGiftValue(target.sumGiveGiftValue())
              .setRoomValue(target.sumRoomValue())
              .setOnlineTime(target.sumAllTargetTime())
              .setMemberSalary(BigDecimal.ZERO)
              .setOwnSalary(BigDecimal.ZERO)
              .setTotalSalary(BigDecimal.ZERO)
              .setSatisfyLevel(Boolean.FALSE);
          allResults.add(defaultTarget);
        });
      }
    });

    return allResults;
  }

    /**
     * 计算上月溢出值.
     */
    private static Map<Long, Long> calculateLastMonthOverflow(List<TeamMemberTarget> targets,
                                                              List<TeamPolicy> teamPolicies) {

        Map<Long, Long> userOverflowMap = new HashMap<>();

        // 按用户分组
        Map<Long, List<TeamMemberTarget>> userTargetMap = targets.stream()
                .collect(Collectors.groupingBy(TeamMemberTarget::getUserId));

        userTargetMap.forEach((userId, userTargets) -> {
            // 找到所有上月历史已结算数据 (history = true)
            List<TeamMemberTarget> historyTargets = userTargets.stream()
                    .filter(t -> Boolean.TRUE.equals(t.getHistory()))
                    .collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(historyTargets)) {
                // 汇总所有历史记录的 acceptGiftValue
                Long totalAcceptGiftValue = historyTargets.stream()
                        .map(TeamMemberTarget::sumAcceptGiftValue)
                        .filter(Objects::nonNull)
                        .reduce(0L, Long::sum);

                // 查找该用户达到的最大等级目标值
                Long levelTargetValue = findLevelTargetValue(totalAcceptGiftValue, teamPolicies);

                // 计算溢出部分
                long overflow = totalAcceptGiftValue - levelTargetValue;
                if (overflow > 0) {
                    userOverflowMap.put(userId, overflow);
                }
            }
        });

        return userOverflowMap;
    }


    /**
     * 根据总收礼物值查找达到的等级目标值.
     *
     * @param totalAcceptGiftValue 总收礼物值
     * @param teamPolicies 团队政策列表(已按level倒序排序)
     * @return 达到的等级目标值
     */
    private static Long findLevelTargetValue(Long totalAcceptGiftValue, List<TeamPolicy> teamPolicies) {
        if (totalAcceptGiftValue == null || totalAcceptGiftValue <= 0) {
            return 0L;
        }

        for (TeamPolicy teamPolicy : teamPolicies) {
            if (totalAcceptGiftValue >= teamPolicy.getTarget()) {
                return teamPolicy.getTarget();
            }
        }

        return 0L;
    }

    /**
     * 将上月溢出值应用到当前月数据并持久化.
     *
     * @param targets 目标数据列表
     * @param userOverflowMap 用户溢出值映射
     */
    private static void applyOverflowToCurrentMonth(List<TeamMemberTarget> targets,
                                                    Map<Long, Long> userOverflowMap) {

        if (userOverflowMap.isEmpty()) {
            return;
        }

        targets.stream()
                .filter(target -> !Boolean.TRUE.equals(target.getHistory()))
                .filter(target -> userOverflowMap.containsKey(target.getUserId()))
                .forEach(target -> {
                    Long overflow = userOverflowMap.get(target.getUserId());

                    // 获取dailyTargets列表
                    List<TeamMemberTargetIndex> dailyTargets = target.getDailyTargets();

                    if (CollectionUtils.isNotEmpty(dailyTargets)) {
                        // 获取最后一个元素
                        TeamMemberTargetIndex lastTarget = dailyTargets.get(dailyTargets.size() - 1);

                        // 设置溢出值
                        lastTarget.setOverFlowGiftValue(overflow);
                        lastTarget.setAcceptGiftValue(lastTarget.getAcceptGiftValue() + overflow);
                        lastTarget.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    }

                    // 添加备注
                    if (target.getRemarks() == null) {
                        target.setRemarks(new ArrayList<>());
                    }
                    target.getRemarks().add("上半月溢出值: " + overflow);

                    // 更新修改时间
                    target.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                });
    }

  /**
   * 计算成员工作情况-钻石政策.
   */
  public static TeamBillMemberTarget calculatorPolicyDiamondTarget(TeamMemberTarget target,
      TeamPolicyManager policy, BigDecimal consumptionPoints) {

    if (Objects.isNull(target)) {
      throw new IllegalArgumentException("target is null.");
    }
    return calculatorPolicyDiamondTarget(List.of(target), policy, consumptionPoints).get(0);
  }

  /**
   * 计算成员日工作情况-钻石政策.
   */
  public static List<TeamBillMemberTarget> calculatorPolicyDiamondDayTarget(
          List<TeamMemberTarget> targets,
          TeamPolicyManager policy) {

    if (CollectionUtils.isEmpty(targets)) {
      return Lists.newArrayList();
    }

    List<TeamPolicy> teamPolicies = Objects.nonNull(policy)
            ? policy.getPolicy().stream()
            .sorted(Comparator.comparing(TeamPolicy::getLevel, Comparator.reverseOrder()))
            .collect(Collectors.toList())
            : Lists.newArrayList();

    return targets.stream().map(target -> {
      log.warn("日账单：" + ZonedDateTimeAsiaRiyadhUtils.nowDateToInt());
      log.warn("target：" + target);
      TeamMemberTargetIndex teamMemberTargetIndex =
              target.getDailyTargets().stream()
                      .filter(item -> item.getDateNumber().equals(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())).findFirst().orElse(new TeamMemberTargetIndex());

      log.warn("日账单：" + teamMemberTargetIndex);
      Long acceptGiftValue = teamMemberTargetIndex.getAcceptGiftValue();
      TeamBillMemberTarget resultTarget = new TeamBillMemberTarget()
              .setTargetId(target.getTimeId())
              .setSysOrigin(target.getSysOrigin())
              .setUserId(target.getUserId())
              .setAcceptGiftValue(teamMemberTargetIndex.getAcceptGiftValue())
              .setGiveGiftValue(teamMemberTargetIndex.getGiveGiftValue())
              .setRoomValue(teamMemberTargetIndex.getRoomValue())
              .setOnlineTime(teamMemberTargetIndex.getOtherOnlineTime())
              .setMemberSalary(BigDecimal.ZERO)
              .setOwnSalary(BigDecimal.ZERO)
              .setRedeemedSalary(BigDecimal.ZERO)
              .setSurplusSalary(BigDecimal.ZERO)
              .setTotalSalary(BigDecimal.ZERO)
              .setSatisfyLevel(Boolean.FALSE);
      if (Objects.isNull(teamMemberTargetIndex.getAcceptGiftValue())) {
        // 日礼物空代表未收到
        return resultTarget;
      }
      for (TeamPolicy teamPolicy : teamPolicies) {
        Long policyGiftValue = NumUtils.isNullDefaultZero(teamPolicy.getTarget());
        if (acceptGiftValue >= policyGiftValue) {
          BigDecimal multiple = BigDecimal.valueOf(acceptGiftValue)
                  .divide(BigDecimal.valueOf(policyGiftValue), 4, RoundingMode.DOWN);
          BigDecimal memberSalary = teamPolicy.getMemberSalary().multiply(multiple).setScale(2, RoundingMode.DOWN);
          BigDecimal ownSalary = teamPolicy.getOwnSalary().multiply(multiple).setScale(2, RoundingMode.DOWN);
          BigDecimal totalSalary = memberSalary.add(ownSalary);
          resultTarget.setMemberSalary(memberSalary);
          resultTarget.setOwnSalary(ownSalary);
          resultTarget.setTotalSalary(totalSalary);
          resultTarget.setLevel(teamPolicy.getLevel());
          resultTarget.setSatisfyLevel(Boolean.TRUE);
          resultTarget.setPropsRewards(teamPolicy.getPropsRewards());
          resultTarget.setPolicyType(policy.getPolicyType());
          return resultTarget;
        }
      }
      return resultTarget;
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  /**
   * 计算成员工作情况-钻石政策.
   */
  public static List<TeamBillMemberTarget> calculatorPolicyDiamondTarget(
      List<TeamMemberTarget> targets,
      TeamPolicyManager policy) {

    if (CollectionUtils.isEmpty(targets)) {
      return Lists.newArrayList();
    }

    List<TeamPolicy> teamPolicies = Objects.nonNull(policy)
        ? policy.getPolicy().stream()
        .sorted(Comparator.comparing(TeamPolicy::getLevel, Comparator.reverseOrder()))
        .collect(Collectors.toList())
        : Lists.newArrayList();

    return targets.stream().map(target -> {
      long targetTimeHours = target.sumAllTargetTime() / 60;
      Long acceptGiftValue = target.sumAcceptGiftValue();
      target.getBillBelong(); // 查询账单信息
      TeamBillMemberTarget resultTarget = new TeamBillMemberTarget()
          .setTargetId(target.getTimeId())
          .setSysOrigin(target.getSysOrigin())
          .setUserId(target.getUserId())
          .setAcceptGiftValue(target.sumAcceptGiftValue())
          .setGiveGiftValue(target.sumGiveGiftValue())
          .setRoomValue(target.sumRoomValue())
          .setOnlineTime(target.sumAllTargetTime())
          .setMemberSalary(BigDecimal.ZERO)
          .setOwnSalary(BigDecimal.ZERO)
          .setRedeemedSalary(BigDecimal.ZERO)
          .setSurplusSalary(BigDecimal.ZERO)
          .setTotalSalary(BigDecimal.ZERO)
          .setSatisfyLevel(Boolean.FALSE);

      for (TeamPolicy teamPolicy : teamPolicies) {
        Long policyOnlineTimeHours = NumUtils.isNullDefaultZero(teamPolicy.getOnlineTime());
        Long policyGiftValue = NumUtils.isNullDefaultZero(teamPolicy.getTarget());
        if (acceptGiftValue >= policyGiftValue) {
          BigDecimal multiple = BigDecimal.valueOf(acceptGiftValue)
              .divide(BigDecimal.valueOf(policyGiftValue), 4, RoundingMode.DOWN);
          BigDecimal memberSalary = teamPolicy.getMemberSalary().multiply(multiple).setScale(0, RoundingMode.DOWN);
          BigDecimal ownSalary = teamPolicy.getOwnSalary().multiply(multiple).setScale(0, RoundingMode.DOWN);
          BigDecimal totalSalary = memberSalary.add(ownSalary);
          resultTarget.setMemberSalary(memberSalary);
          resultTarget.setOwnSalary(ownSalary);
          resultTarget.setTotalSalary(totalSalary);
          resultTarget.setLevel(teamPolicy.getLevel());
          resultTarget.setSatisfyLevel(Boolean.TRUE);
          resultTarget.setPropsRewards(teamPolicy.getPropsRewards());
          resultTarget.setPolicyType(policy.getPolicyType());
          return resultTarget;
        }
      }
      return resultTarget;
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  /**
   * 计算成员工作情况-钻石政策.
   */
  public static List<TeamBillMemberTarget> calculatorPolicyDiamondTarget(
          List<TeamMemberTarget> targets,
          TeamPolicyManager policy, BigDecimal consumptionPoints) {

    if (CollectionUtils.isEmpty(targets)) {
      return Lists.newArrayList();
    }

    List<TeamPolicy> teamPolicies = Objects.nonNull(policy)
            ? policy.getPolicy().stream()
            .sorted(Comparator.comparing(TeamPolicy::getLevel, Comparator.reverseOrder()))
            .collect(Collectors.toList())
            : Lists.newArrayList();

    return targets.stream().map(target -> {
      long targetTimeHours = target.sumAllTargetTime() / 60;
      Long acceptGiftValue = target.sumAcceptGiftValue();
      target.getBillBelong(); // 查询账单信息
      TeamBillMemberTarget resultTarget = new TeamBillMemberTarget()
              .setTargetId(target.getTimeId())
              .setSysOrigin(target.getSysOrigin())
              .setUserId(target.getUserId())
              .setAcceptGiftValue(target.sumAcceptGiftValue())
              .setGiveGiftValue(target.sumGiveGiftValue())
              .setRoomValue(target.sumRoomValue())
              .setOnlineTime(target.sumAllTargetTime())
              .setMemberSalary(BigDecimal.ZERO)
              .setOwnSalary(BigDecimal.ZERO)
              .setRedeemedSalary(consumptionPoints)
              .setSurplusSalary(BigDecimal.ZERO)
              .setTotalSalary(BigDecimal.ZERO)
              .setSatisfyLevel(Boolean.FALSE);

      for (TeamPolicy teamPolicy : teamPolicies) {
        Long policyOnlineTimeHours = NumUtils.isNullDefaultZero(teamPolicy.getOnlineTime());
        Long policyGiftValue = NumUtils.isNullDefaultZero(teamPolicy.getTarget());
        if (acceptGiftValue >= policyGiftValue) {
          BigDecimal multiple = BigDecimal.valueOf(acceptGiftValue)
                  .divide(BigDecimal.valueOf(policyGiftValue), 4, RoundingMode.DOWN);
          BigDecimal memberSalary = teamPolicy.getMemberSalary().multiply(multiple).setScale(0, RoundingMode.DOWN);
          BigDecimal ownSalary = teamPolicy.getOwnSalary().multiply(multiple).setScale(0, RoundingMode.DOWN);
          BigDecimal totalSalary = memberSalary.add(ownSalary);
          // 用户剩余工资=用户工资-用户已兑换工资
          BigDecimal surplusSalary = memberSalary.subtract(resultTarget.getRedeemedSalary());

          resultTarget.setSurplusSalary(surplusSalary);
          resultTarget.setMemberSalary(memberSalary);
          resultTarget.setOwnSalary(ownSalary);
          resultTarget.setTotalSalary(totalSalary);
          resultTarget.setLevel(teamPolicy.getLevel());
          resultTarget.setSatisfyLevel(Boolean.TRUE);
          resultTarget.setPropsRewards(teamPolicy.getPropsRewards());
          resultTarget.setPolicyType(policy.getPolicyType());
          return resultTarget;
        }
      }
      return resultTarget;
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }


  public static Integer getCalcBillBelong() {
    LocalDate now = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
    return calculateCurrentBillBelong(now);
  }

  /**
   * 计算当前账期的 billBelong
   * 规则：
   * - 1-15号：当前账期是本月1号（20251001）
   * - 16-月末：当前账期是本月16号（20251016）
   */
  private static Integer calculateCurrentBillBelong(LocalDate now) {
    int day = now.getDayOfMonth();
    LocalDate billDate;

    if (day < 16) {
      // 当前是上半月，账期开始日期是本月1号
      billDate = now.withDayOfMonth(1);
    } else {
      // 当前是下半月，账期开始日期是本月16号
      billDate = now.withDayOfMonth(16);
    }

    return Integer.parseInt(billDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
  }

  /**
   * 解析 billBelong 为日期范围.
   * 兼容两种格式：
   * 1. 旧格式（6位）：202510 表示整月 (2025年10月)
   * 2. 新格式（8位）：20251001 或 20251016 表示半月周期
   *
   * @param billBelong 账单归属
   * @return 日期范围数组 [startDate, endDate]，格式：yyyy.MM.dd
   */
  public static String[] parseBillBelongToDateRange(Integer billBelong) {
    if (billBelong == null) {
      return new String[]{"", ""};
    }

    String billBelongStr = String.valueOf(billBelong);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");

    // 判断是旧格式（6位）还是新格式（8位）
    if (billBelongStr.length() == 6) {
      // 旧格式：202510 表示整月
      int year = Integer.parseInt(billBelongStr.substring(0, 4));
      int month = Integer.parseInt(billBelongStr.substring(4, 6));

      YearMonth yearMonth = YearMonth.of(year, month);
      LocalDate startDate = yearMonth.atDay(1);
      LocalDate endDate = yearMonth.atEndOfMonth();

      return new String[]{
          startDate.format(formatter),
          endDate.format(formatter)
      };
    } else if (billBelongStr.length() == 8) {
      // 新格式：20251001 或 20251016 表示半月周期
      int year = Integer.parseInt(billBelongStr.substring(0, 4));
      int month = Integer.parseInt(billBelongStr.substring(4, 6));
      int day = Integer.parseInt(billBelongStr.substring(6, 8));

      LocalDate startDate = LocalDate.of(year, month, day);
      LocalDate endDate;

      if (day == 1) {
        // 1-15号的账单周期
        endDate = LocalDate.of(year, month, 15);
      } else {
        // 16-月末的账单周期
        endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());
      }

      return new String[]{
          startDate.format(formatter),
          endDate.format(formatter)
      };
    } else {
      // 格式不正确，返回空字符串
      return new String[]{"", ""};
    }
  }

  public static String parseBillBelongToDateRangeStr(Integer billBelong) {
    String[] strings = parseBillBelongToDateRange(billBelong);
    return strings[0] + "-" + strings[1];
  }

    /**
     * 获取月度账期（用于批次模式）
     * 返回格式：202511
     */
    public static Integer getMonthlyBillBelong() {
        LocalDate now = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
        return Integer.parseInt(now.format(DateTimeFormatter.ofPattern("yyyyMM")));
    }

    /**
     * 获取当前结算批次
     * 返回：1 = 上半月, 2 = 下半月
     */
    public static Integer getCurrentSettlementBatch() {
        LocalDate now = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
        return now.getDayOfMonth() < 16 ? 1 : 2;
    }

    /**
     * 判断是否启用批次模式（通过区域配置）
     */
    public static Boolean isBatchModeEnabled(String region) {
        // 从配置中读取，或者硬编码
        // 例如：return "SA".equals(region); // 沙特地区启用批次模式
        return true;
    }

    /**
     * 从 billBelong 提取月份（兼容新旧格式）
     * 20251101 -> 202511
     * 20251116 -> 202511
     */
    public static Integer extractMonth(Integer billBelong) {
        if (billBelong == null) {
            return null;
        }
        String billStr = String.valueOf(billBelong);
        if (billStr.length() == 6) {
            // 已经是月度格式
            return billBelong;
        }
        // 提取年月部分
        return Integer.parseInt(billStr.substring(0, 6));
    }

    /**
     * 从 billBelong 提取批次号（兼容新旧格式）
     * 20251101 -> 1
     * 20251116 -> 2
     */
    public static Integer extractBatch(Integer billBelong) {
        if (billBelong == null) {
            return null;
        }
        String billStr = String.valueOf(billBelong);
        if (billStr.length() != 8) {
            return null;
        }
        int day = Integer.parseInt(billStr.substring(6, 8));
        return day == 1 ? 1 : 2;
    }

    /**
     * 生成批次标题
     * 202511, 1 -> "2025年11月（上半月）"
     * 202511, 2 -> "2025年11月（下半月）"
     */
    public static String generateBatchTitle(Integer monthlyBillBelong, Integer batchNumber) {
        if (monthlyBillBelong == null) {
            return "";
        }
        String billStr = String.valueOf(monthlyBillBelong);
        int year = Integer.parseInt(billStr.substring(0, 4));
        int month = Integer.parseInt(billStr.substring(4, 6));

        String batchDesc = batchNumber == 1 ? "上半月" : "下半月";
        return String.format("%d年%d月（%s）", year, month, batchDesc);
    }

  public static LocalDateTime getBillBelongStartTime(Integer billBelong) {
    // billBelong 格式：20251101 或 20251116
    int year = billBelong / 10000;      // 2025
    int month = (billBelong / 100) % 100;  // 11
    int day = billBelong % 100;         // 01 或 16

    return LocalDateTime.of(year, month, day, 0, 0, 0);
  }

  public static LocalDateTime getBillBelongEndTime(Integer billBelong) {
    // billBelong 格式：20251101 或 20251116
    int year = billBelong / 10000;      // 2025
    int month = (billBelong / 100) % 100;  // 11
    int day = billBelong % 100;         // 01 或 16

    LocalDateTime startTime = LocalDateTime.of(year, month, day, 0, 0, 0);

    if (day == 1) {
      // 如果是1号，结束时间是当月16号0点
      return LocalDateTime.of(year, month, 16, 0, 0, 0);
    } else {
      // 如果是16号，结束时间是下个月1号0点
      return startTime.plusMonths(1).withDayOfMonth(1);
    }
  }

}
