package com.red.circle.other.app.command.team.query;

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.other.app.convertor.team.TeamAppConvertor;
import com.red.circle.other.app.dto.clientobject.team.TeamBillCO;
import com.red.circle.other.app.dto.clientobject.team.TeamBillSettleResultCO;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamBillCycle;
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.mongo.service.team.team.TeamBillCycleService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
import com.red.circle.other.infra.database.mongo.service.user.region.SysRegionConfigService;
import com.red.circle.other.infra.database.rds.entity.team.BillDiamondBalance;
import com.red.circle.other.infra.database.rds.entity.team.BillDiamondBalanceDetails;
import com.red.circle.other.infra.database.rds.service.team.BillDiamondBalanceDetailsService;
import com.red.circle.other.infra.database.rds.service.team.BillDiamondBalanceService;
import com.red.circle.other.inner.enums.team.TeamBillCycleStatus;
import com.red.circle.other.inner.enums.team.TeamMemberTargetIndex;
import com.red.circle.other.inner.enums.team.TeamMemberTargetStatus;
import com.red.circle.other.inner.enums.team.TeamPolicyTypeEnum;
import com.red.circle.tool.core.collection.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 团队账单.
 *
 * @author pengliang on 2022/12/27
 */
@Component
@RequiredArgsConstructor
public class TeamBillQryExe {

  private static final Logger log = LoggerFactory.getLogger(TeamBillQryExe.class);
  private final TeamAppConvertor teamAppConvertor;
  private final TeamBillCycleService teamBillCycleService;
  private final TeamPolicyManagerService teamPolicyManagerService;
  private final SysRegionConfigService sysRegionConfigService;
  private final BillDiamondBalanceService billDiamondBalanceService;
  private final BillDiamondBalanceDetailsService billDiamondBalanceDetailsService;

  public List<TeamBillCO> execute(AppIdLongCmd cmd) {

    List<TeamBillCycle> teamBillCycles = teamBillCycleService.listLatestBill(cmd.getId(),
        PageConstant.MAX_LIMIT_SIZE);

    if (CollectionUtils.isEmpty(teamBillCycles)) {
      return Lists.newArrayList();
    }
    List<TeamBillCO> teamBill = teamBillCycles.stream().map(teamAppConvertor::toTeamBillCO).collect(Collectors.toList());
    for (TeamBillCO teamBillCO : teamBill) {
      if (!Objects.isNull(teamBillCO.getSettleResult())) {
        BillDiamondBalance billDiamondBalance = billDiamondBalanceService
                .getEntityByBillBelongAndUserId(SysOriginPlatformEnum.TARAB.name(), teamBillCO.getBillBelong(), cmd.getReqUserId());
        if (!Objects.isNull(billDiamondBalance)) {
          teamBillCO.getSettleResult().setRedeemedSalary(Objects.isNull(billDiamondBalance.getConsumptionPoints()) ? BigDecimal.ZERO : billDiamondBalance.getConsumptionPoints());
        } else {
          teamBillCO.getSettleResult().setRedeemedSalary(BigDecimal.ZERO);
        }
        // 用户剩余工资=用户工资-用户已兑换工资
        BigDecimal surplusSalary = teamBillCO.getSettleResult().getOwnSalary().subtract(teamBillCO.getSettleResult().getRedeemedSalary());
        teamBillCO.getSettleResult().setSurplusSalary(surplusSalary);
      }
    }
    return teamBill;
  }

  public List<TeamBillCO> executeAgent(AppIdLongCmd cmd) {

    List<TeamBillCycle> teamBillCycles = teamBillCycleService.listLatestBill(cmd.getId(),
            PageConstant.MAX_LIMIT_SIZE);
    
    if (CollectionUtils.isEmpty(teamBillCycles)) {
      return Lists.newArrayList();
    }
    List<TeamBillCO> teamBill = teamBillCycles.stream().map(teamAppConvertor::toTeamBillCO).collect(Collectors.toList());
    for (TeamBillCO teamBillCO : teamBill) {
      if (!Objects.isNull(teamBillCO.getSettleResult())) {
        BillDiamondBalance billDiamondBalance = billDiamondBalanceService
                .getEntityByBillBelongAndUserId(SysOriginPlatformEnum.TARAB.name(), teamBillCO.getBillBelong(), cmd.getReqUserId());
        if (!Objects.isNull(billDiamondBalance)) {
          teamBillCO.getSettleResult().setRedeemedSalary(Objects.isNull(billDiamondBalance.getAgentConsumptionPoints()) ? BigDecimal.ZERO : billDiamondBalance.getAgentConsumptionPoints());
        } else {
          teamBillCO.getSettleResult().setRedeemedSalary(BigDecimal.ZERO);
        }
        // 用户剩余工资=用户工资-用户已兑换工资
        BigDecimal surplusSalary = teamBillCO.getSettleResult().getOwnSalary().subtract(teamBillCO.getSettleResult().getRedeemedSalary());
        teamBillCO.getSettleResult().setSurplusSalary(surplusSalary);
      }
    }

    // 经产品和运营确认，如果是钻石政策并且是日结区域，显示日账单列表
    TeamPolicyManager policy = teamPolicyManagerService.getReleaseByRegionAndType(SysOriginPlatformEnum.LIKEI.name(), teamBillCycles.get(0).getRegion());
    if (Objects.isNull(policy)) {
      return teamBill;
    }
    SysRegionConfig regionConfig = sysRegionConfigService.getById(policy.getRegion());
    Map<String, String> metadata = getMetadata(regionConfig);
    boolean isOpenDailyAutoSalary = isOpenDailyAutoSalary(metadata);
    //log.warn("regionConfig" + regionConfig);
    if (Objects.equals(TeamPolicyTypeEnum.SALARY_DIAMOND.name(), policy.getPolicyType())
          && Boolean.TRUE.equals(isOpenDailyAutoSalary)) {
      List<TeamBillCO> teamDayBill = new ArrayList<>();
      for (TeamBillCO teamBillCO : teamBill) {
        List<BillDiamondBalanceDetails> billDiamondBalances = billDiamondBalanceDetailsService.getEntityByBillBelongAndTeamId(SysOriginPlatformEnum.TARAB.name(), teamBillCO.getBillBelong(), cmd.getId());
        /*List<BillDiamondBalanceDetails> billBalance = billDiamondBalances.stream().distinct()
                .sorted(Comparator.comparing(BillDiamondBalanceDetails::getBillBelongDay).reversed()).toList();*/
        Map<Integer, List<BillDiamondBalanceDetails>> billBalanceMap = billDiamondBalances.stream()
                .collect(Collectors.groupingBy(BillDiamondBalanceDetails::getBillBelongDay));;
        Map<Integer, List<BillDiamondBalanceDetails>> sortedMap = new TreeMap<>(Comparator.reverseOrder());
        sortedMap.putAll(billBalanceMap);

        for(Map.Entry<Integer, List<BillDiamondBalanceDetails>> entry : sortedMap.entrySet()){
          Integer billBelongDay = entry.getKey();

          BillDiamondBalanceDetails diamondBalance = billDiamondBalances.stream()
                  .filter(item -> item.getUserId().equals(cmd.getReqUserId()) &&
                          item.getBillBelongDay().equals(billBelongDay)).findFirst().orElse(null);
          if (Objects.isNull(diamondBalance)) {
            continue;
          }

          TeamBillCO teamBillInfo = new TeamBillCO();
          teamBillInfo.setId(teamBillCO.getId());
          teamBillInfo.setBillTitle(teamBillCO.getBillTitle());
          teamBillInfo.setBillBelong(teamBillCO.getBillBelong());
          teamBillInfo.setBillDayTitle(diamondBalance.getBillBelongDay() + "");
          if (billBelongDay.equals(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())) {
            teamBillInfo.setGoldStatus(Boolean.TRUE);
            teamBillInfo.setStatus(TeamBillCycleStatus.UNPAID.name());
          } else {
            teamBillInfo.setGoldStatus(Boolean.FALSE);
            teamBillInfo.setStatus(TeamBillCycleStatus.PAY_OUT.name());
          }
          teamBillInfo.setMemberTargetStatus(TeamMemberTargetStatus.AUTO.name());
          TeamBillSettleResultCO teamBillSettleResultCO = new TeamBillSettleResultCO();
          teamBillSettleResultCO.setWorkMembers(billDiamondBalances.stream().filter(item -> item.getBillBelongDay().equals(billBelongDay)).toList().size());//工作人数
          teamBillSettleResultCO.setFinishMembers(billDiamondBalances.stream().filter(item -> item.getBillBelongDay().equals(billBelongDay)).toList().size());//完成人数
          BigDecimal memberSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billBelongDay))
                  .map(item -> item.getEarnPoints().setScale(0, RoundingMode.DOWN))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setMemberSalary(memberSalary);//成员工资
          BigDecimal ownSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billBelongDay))
                  .map(item -> item.getAgentEarnPoints().setScale(0, RoundingMode.DOWN))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setOwnSalary(ownSalary);//拥有者工资
          BigDecimal totalSalary = memberSalary.add(ownSalary);//工资合计memberSalary+ownSalary.
          teamBillSettleResultCO.setTotalSalary(totalSalary);
          BigDecimal redeemedSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billBelongDay) && item.getUserId().equals(cmd.getReqUserId()))
                  .map(item -> item.getAgentConsumptionPoints().setScale(0, RoundingMode.DOWN))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setRedeemedSalary(redeemedSalary);//已兑换工资（钻石）
          BigDecimal surplusSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billBelongDay) && item.getUserId().equals(cmd.getReqUserId()))
                  .map(item -> item.getAgentBalance().setScale(0, RoundingMode.DOWN))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setSurplusSalary(surplusSalary);// 剩余工资（钻石）

          teamBillInfo.setSettleResult(teamBillSettleResultCO);
          teamDayBill.add(teamBillInfo);
        }

        /*for (BillDiamondBalanceDetails billDiamondBalance : billBalance) {
          BillDiamondBalanceDetails diamondBalance = billDiamondBalances.stream()
                  .filter(item -> item.getUserId().equals(cmd.getReqUserId()) &&
                          item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay())).findFirst().orElse(null);

          TeamBillCO teamBillInfo = new TeamBillCO();
          teamBillInfo.setId(teamBillCO.getId());
          teamBillInfo.setBillTitle(teamBillCO.getBillTitle());
          teamBillInfo.setBillBelong(teamBillCO.getBillBelong());
          teamBillInfo.setBillDayTitle(diamondBalance.getBillBelongDay()+"");
          if (billDiamondBalance.getBillBelongDay().equals(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())) {
            teamBillInfo.setGoldStatus(Boolean.TRUE);
            teamBillInfo.setStatus(TeamBillCycleStatus.UNPAID.name());
          } else {
            teamBillInfo.setGoldStatus(Boolean.FALSE);
            teamBillInfo.setStatus(TeamBillCycleStatus.PAY_OUT.name());
          }
          teamBillInfo.setMemberTargetStatus(TeamMemberTargetStatus.AUTO.name());
          TeamBillSettleResultCO teamBillSettleResultCO = new TeamBillSettleResultCO();
          teamBillSettleResultCO.setWorkMembers(billDiamondBalances.stream().filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay())).toList().size());//工作人数
          teamBillSettleResultCO.setFinishMembers(billDiamondBalances.stream().filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay())).toList().size());//完成人数
          BigDecimal memberSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay()))
                  .map(BillDiamondBalanceDetails::getEarnPoints)
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setMemberSalary(memberSalary);//成员工资
          BigDecimal ownSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay()))
                  .map(BillDiamondBalanceDetails::getAgentEarnPoints)
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setOwnSalary(ownSalary);//拥有者工资
          teamBillSettleResultCO.setTotalSalary(memberSalary.add(ownSalary));//工资合计memberSalary+ownSalary.
          BigDecimal redeemedSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay()) && item.getUserId().equals(cmd.getReqUserId()))
                  .map(balance -> balance.getConsumptionPoints().add(balance.getAgentConsumptionPoints()))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setRedeemedSalary(redeemedSalary);//已兑换工资（钻石）
          BigDecimal surplusSalary = billDiamondBalances.stream()
                  .filter(item -> item.getBillBelongDay().equals(billDiamondBalance.getBillBelongDay()) && item.getUserId().equals(cmd.getReqUserId()))
                  .map(balance -> balance.getBalance().add(balance.getAgentBalance()))
                  .reduce(BigDecimal.ZERO, BigDecimal::add);
          teamBillSettleResultCO.setSurplusSalary(surplusSalary);// 剩余工资（钻石）

          teamBillInfo.setSettleResult(teamBillSettleResultCO);
          teamDayBill.add(teamBillInfo);
        }*/
      }

      return teamDayBill;
    }
    return teamBill;
  }

  private static List<TeamMemberTargetIndex> filter(List<TeamMemberTargetIndex> stringList, Integer dateNumBer) {
    stringList = stringList.stream().filter(item -> {
      return item.getDateNumber().equals(dateNumBer);
    }).collect(Collectors.toList());
    return stringList;
  }

  private Map<String, String> getMetadata(SysRegionConfig regionConfig) {
    return Optional.ofNullable(regionConfig)
            .map(SysRegionConfig::getMetadata).orElseGet(CollectionUtils::newHashMap);
  }

  /**
   * 是否开启每日自动结算工资.
   */
  private boolean isOpenDailyAutoSalary(Map<String, String> metadata) {
    return Objects.equals(metadata.get("openDailyAutoSalary"), "true");
  }
}
