package com.red.circle.other.infra.common.team.decay;

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.domain.model.user.ability.RegionConfig;
import com.red.circle.other.infra.convertor.team.TeamInfraConvertor;
import com.red.circle.other.infra.database.mongo.dto.team.TeamBillMemberTarget;
import com.red.circle.other.infra.database.mongo.dto.team.query.TeamMemberTargetQuery;
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.team.team.TeamProfile;
import com.red.circle.other.infra.database.mongo.service.team.TeamBillCycleUtils;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamBillCycleService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
import com.red.circle.other.infra.database.rds.entity.team.BillDiamondBalance;
import com.red.circle.other.infra.database.rds.service.team.BillDiamondBalanceService;
import com.red.circle.other.infra.database.rds.service.user.user.UserRelationshipCounterService;
import com.red.circle.other.inner.enums.team.TeamPolicyTypeEnum;
import com.red.circle.other.inner.model.cmd.team.TeamMemberWorkQryCmd;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkDTO;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkTargetDTO;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberWorkTargetSettleDTO;
import com.red.circle.other.inner.enums.team.TeamBillCycleStatus;
import com.red.circle.other.inner.enums.team.TeamMemberTargetSettlementResult;
import com.red.circle.other.inner.enums.team.TeamMemberTargetStatus;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.text.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 团队成员工作情况.
 *  TODO mark pl [腐烂的， 充满坏味道].
 *
 * @author lisizhe 2023/11/2  15:43
 */
@Component
@RequiredArgsConstructor
public class ListMemberWorkDecay {

  private final UserRegionGateway userRegionGateway;
  private final UserProfileGateway userProfileGateway;
  private final TeamInfraConvertor teamInfraConvertor;
  private final TeamProfileService teamProfileService;
  private final TeamBillCycleService teamBillCycleService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final TeamPolicyManagerService teamPolicyManagerService;
  private final UserRelationshipCounterService userRelationshipCounterService;
  private final BillDiamondBalanceService billDiamondBalanceService;


  public List<TeamMemberWorkDTO> execute(TeamMemberWorkQryCmd query) {

    if (StringUtils.isBlank(query.getSysOrigin())) {
      return Lists.newArrayList();
    }

    TeamMemberTargetQuery targetQuery = teamInfraConvertor.toTeamMemberTargetQuery(query);

    if (Objects.nonNull(query.getOwnUserId())) {

      TeamProfile teamProfile = teamProfileService.getByOwnUserId(query.getOwnUserId());

      if (Objects.isNull(teamProfile)) {
        return Lists.newArrayList();
      }

      targetQuery.setTeamId(teamProfile.getId());
    }

    List<TeamMemberTarget> teamMemberTargets = teamMemberTargetService.list(targetQuery);

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

    Map<String, TeamPolicyManager> policyManagerMap = getPolicyManagerMap(query);

    Map<Long, TeamProfile> teamProfileMap = teamProfileService.mapProfileByIds(
        teamMemberTargets.stream().map(TeamMemberTarget::getTeamId).collect(Collectors.toSet())
    );

    Map<Long, UserProfile> userProfileMap = userProfileGateway.mapByUserIds(
        Stream.of(
            teamProfileMap.values().stream().map(TeamProfile::getOwnUserId)
                .collect(Collectors.toList()),
            teamMemberTargets.stream().map(TeamMemberTarget::getUserId)
                .collect(Collectors.toList())
        ).flatMap(Collection::stream).collect(Collectors.toSet()));

    Map<String, TeamBillCycle> teamBillCycleMap = teamBillCycleService.mapByBillIds(
        teamMemberTargets.stream().map(TeamMemberTarget::getTeamId)
            .collect(Collectors.toSet()),
        teamMemberTargets.stream().map(TeamMemberTarget::getBillBelong)
            .collect(Collectors.toSet())
    );

    Map<Long, Long> fansNumberByUserId = userRelationshipCounterService
        .mapFansNumberByUserId(
            teamMemberTargets.stream().map(TeamMemberTarget::getUserId)
                .collect(Collectors.toSet()));

    return teamMemberTargets.stream().map(target -> {
      TeamBillCycle teamBillCycle = teamBillCycleMap.get(
          target.getTeamId() + "_" + target.getBillBelong());
      if (Objects.isNull(teamBillCycle)) {
        return null;
      }
      TeamProfile teamProfile = teamProfileMap.get(target.getTeamId());

      TeamPolicyManager regionPolicyManager = TeamBillCycleUtils.getPolicyFromMap(
              policyManagerMap,
              target.getRegion(),
              target.getCountryCode());

      TeamMemberWorkTargetDTO workTarget = new TeamMemberWorkTargetDTO()
          .setAcceptGiftValue(target.sumAcceptGiftValue())
          .setEffectiveDay(target.sumEffectiveDay())
          .setGiveGiftValue(target.sumGiveGiftValue())
          .setRoomValue(target.sumRoomValue())
          .setOwnOnlineTime(target.sumOwnOnlineTime())
          .setOtherOnlineTime(target.sumOtherOnlineTime())
          .setDailyTargets(Optional.ofNullable(target.getDailyTargets())
              .map(daily -> daily.stream().map(teamInfraConvertor::toTeamMemberWorkDailyTargetDTO)
                  .collect(Collectors.toList()))
              .orElse(Lists.newArrayList()));

      if (Objects.nonNull(target.getSettlementResult()) && !Objects.equals(
          teamBillCycle.getStatus(),
          TeamBillCycleStatus.UNPAID)) {

        TeamMemberTargetSettlementResult settleResult = target.getSettlementResult();

        TeamMemberWorkTargetSettleDTO targetSettleVO = teamInfraConvertor.toTeamMemberWorkTargetSettleDTO(
            settleResult);
        targetSettleVO.setPropsRewardReceive(settleResult.getPropsReceived());
        if (Objects.nonNull(regionPolicyManager)
                && Objects.nonNull(regionPolicyManager.getPolicyType())
                && Objects.equals(TeamPolicyTypeEnum.SALARY_DIAMOND.name(),regionPolicyManager.getPolicyType())) {
          targetSettleVO.setPolicyType(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
          // 主播工作列表新增剩余钻石
          BillDiamondBalance billDiamondBalance = billDiamondBalanceService.getEntityByBillBelongAndUserId(SysOriginPlatformEnum.TARAB.name(), target.getBillBelong(), target.getUserId());
          if (Objects.nonNull(billDiamondBalance)) {
            BigDecimal ownBalance = billDiamondBalance.getBalance().setScale(0, RoundingMode.DOWN);
            BigDecimal agentBalance = billDiamondBalance.getAgentBalance().setScale(0, RoundingMode.DOWN);
            BigDecimal balance = ownBalance.add(agentBalance);
            BigDecimal consumptionPoints = billDiamondBalance.getConsumptionPoints().add(billDiamondBalance.getAgentConsumptionPoints());

            targetSettleVO.setSurplusDiamonds(balance);
            targetSettleVO.setExchangeDiamonds(consumptionPoints);
            targetSettleVO.setDeductDiamonds(BigDecimal.ZERO);
          } else {
            targetSettleVO.setSurplusDiamonds(targetSettleVO.getTotalSalary());
            targetSettleVO.setExchangeDiamonds(BigDecimal.ZERO);
            targetSettleVO.setDeductDiamonds(BigDecimal.ZERO);
          }
        } else {
          targetSettleVO.setPolicyType(TeamPolicyTypeEnum.MONEY.name());
        }
        workTarget.setSettleRes(targetSettleVO);

      } else {

        TeamBillMemberTarget billMemberTarget = calculatorTarget(target, regionPolicyManager);

        TeamMemberWorkTargetSettleDTO workTargetSettleVO = teamInfraConvertor.toTeamMemberWorkTargetSettleDTO(
            billMemberTarget);
        workTargetSettleVO.setPropsRewardReceive(Boolean.FALSE);

        if (Objects.nonNull(regionPolicyManager)
                && Objects.nonNull(regionPolicyManager.getPolicyType())
                && Objects.equals(TeamPolicyTypeEnum.SALARY_DIAMOND.name(),regionPolicyManager.getPolicyType())) {
          workTargetSettleVO.setPolicyType(TeamPolicyTypeEnum.SALARY_DIAMOND.name());
        } else {
          workTargetSettleVO.setPolicyType(TeamPolicyTypeEnum.MONEY.name());
        }

        // 主播工作列表新增剩余钻石
        BillDiamondBalance billDiamondBalance = billDiamondBalanceService.getEntityByBillBelongAndUserId(SysOriginPlatformEnum.TARAB.name(), target.getBillBelong(), target.getUserId());
        if (Objects.nonNull(billDiamondBalance)) {
          BigDecimal ownBalance = billDiamondBalance.getBalance().setScale(0, RoundingMode.DOWN);
          BigDecimal agentBalance = billDiamondBalance.getAgentBalance().setScale(0, RoundingMode.DOWN);
          BigDecimal balance = ownBalance.add(agentBalance);
          BigDecimal consumptionPoints = billDiamondBalance.getConsumptionPoints().add(billDiamondBalance.getAgentConsumptionPoints());

          workTargetSettleVO.setSurplusDiamonds(balance);
          workTargetSettleVO.setExchangeDiamonds(consumptionPoints);
          workTargetSettleVO.setDeductDiamonds(BigDecimal.ZERO);
        } else {
          workTargetSettleVO.setSurplusDiamonds(workTargetSettleVO.getTotalSalary());
          workTargetSettleVO.setExchangeDiamonds(BigDecimal.ZERO);
          workTargetSettleVO.setDeductDiamonds(BigDecimal.ZERO);
        }

        // 结算账单.
        workTarget.setSettleRes(workTargetSettleVO);
      }

      return new TeamMemberWorkDTO()
          .setId(target.getTimeId())
          .setSysOrigin(target.getSysOrigin())
          .setSalarySettlementMode(
              Objects.equals(target.getStatus(), TeamMemberTargetStatus.AUTO) ? "日结" : "月结")
          .setTeamProfile(teamInfraConvertor.toTeamProfileDTO(teamProfile))
          .setBillBelong(teamBillCycle.getBillBelong())
          .setMemberId(userProfileMap.get(target.getUserId()).getId())
          .setOwnUserId(
              Objects.nonNull(teamProfile) ? userProfileMap.get(teamProfile.getOwnUserId()).getId()
                  : null)
          .setBillTitle(teamBillCycle.getBillTitle())
          .setBillStatus(teamBillCycle.getStatus().name())
          .setMemberFans(fansNumberByUserId.get(target.getUserId()))
          .setTarget(workTarget)
          .setCreateTime(target.getCreateTime())
          .setUpdateTime(target.getUpdateTime());
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  private TeamBillMemberTarget calculatorTarget(TeamMemberTarget target,
                                                TeamPolicyManager policy) {
    //2fun新增钻石政策
    if (Objects.isNull(policy) || Objects.isNull(policy.getPolicyType()) || Objects.equals("MONEY", policy.getPolicyType())) {
      return TeamBillCycleUtils.calculatorPolicyTarget(target, policy);
    }
    BillDiamondBalance billDiamondBalance = billDiamondBalanceService.getEntityByBillBelongAndUserId(target.getSysOrigin(), target.getBillBelong(), target.getUserId());

    return TeamBillCycleUtils.calculatorPolicyDiamondTarget(target, policy, Objects.nonNull(billDiamondBalance) ? billDiamondBalance.getConsumptionPoints() : BigDecimal.ZERO);

  }

  private Map<String, TeamPolicyManager> getPolicyManagerMap(TeamMemberWorkQryCmd query) {
    return teamPolicyManagerService.mapRegionReleaseWithCountry(listSysRegionConfig(query.getSysOrigin()));
  }

  private Set<String> listSysRegionConfig(String sysOrigin) {
    List<RegionConfig> regionConfigList = userRegionGateway.listRegionConfigBySysOrigin(sysOrigin);
    return Optional.ofNullable(regionConfigList)
        .map(region -> region.stream().map(
            RegionConfig::getId).collect(Collectors.toSet()))
        .orElse(Set.of());
  }

}
