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


import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.app.AppUserIdCmd;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.other.app.convertor.team.TeamAppConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.team.TeamMemberWorkBillCO;
import com.red.circle.other.app.dto.clientobject.team.TeamMemberWorkCO;
import com.red.circle.other.app.dto.clientobject.team.TeamMemberWorkDailyTargetCO;
import com.red.circle.other.app.dto.clientobject.team.TeamMemberWorkTargetCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.cache.service.user.SysRegionCacheService;
import com.red.circle.other.infra.database.mongo.dto.team.TeamBillMemberTarget;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamBillCycle;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
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.TeamBillCycleUtils;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamBillCycleService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
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.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.asserts.user.UserErrorCode;
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.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.enums.team.TeamBillCycleStatus;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.LocalDateTimeUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.num.NumUtils;

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

import com.red.circle.wallet.inner.endpoint.diamond.SalaryDiamondRunningWaterClient;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author pengliang on 2022/12/26
 */
@Component
@RequiredArgsConstructor
public class TeamMemberWorkQryExe {

    private static final Logger log = LoggerFactory.getLogger(TeamMemberWorkQryExe.class);
    private final TeamAppConvertor teamAppConvertor;
  private final TeamMemberService teamMemberService;
  private final UserProfileGateway userProfileGateway;
  private final TeamBillCycleService teamBillCycleService;
  private final TeamMemberTargetService teamMemberTargetService;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final TeamPolicyManagerService teamPolicyManagerService;
  private final BillDiamondBalanceService billDiamondBalanceService;
    private final BillDiamondBalanceDetailsService billDiamondBalanceDetailsService;
    private final SysRegionConfigService sysRegionConfigService;
    private final SalaryDiamondRunningWaterClient salaryDiamondRunningWaterClient;

  public TeamMemberWorkCO execute(AppUserIdCmd cmd) {
    TeamMember teamMember = teamMemberService.getByMemberId(cmd.getUserId());
    ResponseAssert.notNull(TeamErrorCode.NOT_TEAM_MEMBER, teamMember);
    UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(teamMember.getMemberId()));
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);

    Integer billBelong = Integer.valueOf(LocalDateTimeUtils.format(
        LocalDateTimeUtils.convert(teamMember.getCreateTime().getTime()), "yyyyMM"));

    List<TeamBillCycle> teamBillCycles = teamBillCycleService.listByGeBillBelong(
        teamMember.getTeamId(), billBelong, 5);

    if (CollectionUtils.isEmpty(teamBillCycles)) {
      return new TeamMemberWorkCO()
          .setMemberProfile(userProfile)
          .setTargets(Lists.newArrayList());
    }

    Map<Integer, TeamMemberTarget> teamMemberTargetMap = Optional.ofNullable(
            teamMemberTargetService.listByGeBillBelong(
                teamMember.getTeamId(), teamMember.getMemberId(), billBelong))
        .map(target -> target.stream()
            .collect(Collectors.toMap(TeamMemberTarget::getBillBelong, v -> v)))
        .orElseGet(Maps::newHashMap);

    List<TeamBillCycle> unpaidBillCycles = teamBillCycles.stream()
        .filter(
            teamBillCycle -> Objects.equals(teamBillCycle.getStatus(), TeamBillCycleStatus.UNPAID))
        .collect(Collectors.toList());

    // 使用新的方法，支持 countryCode
    Map<String, TeamPolicyManager> regionPolicy = teamPolicyManagerService.mapRegionReleaseWithCountry(
        unpaidBillCycles.stream().map(TeamBillCycle::getRegion).collect(Collectors.toSet())
    );

      BigDecimal settledAndSumSalary = teamMemberTargetService.listMemberSettledAndSumSalary(teamMember.getTeamId(), teamMember.getMemberId(), teamMember.getRole());


    TeamMemberWorkCO teamMemberWorkCO = new TeamMemberWorkCO()
      .setMemberProfile(userProfile)
      .setTargets(teamBillCycles.stream()
              .map(bill -> {
                  TeamMemberWorkBillCO co = new TeamMemberWorkBillCO()
                          .setId(bill.getId())
                          .setBillBelong(bill.getBillBelong())
                          .setBillTitle(TeamBillCycleUtils.parseBillBelongToDateRangeStr(bill.getBillBelong()))
                          .setStatus(bill.getStatus().name());

                  TeamMemberTarget target = teamMemberTargetMap.get(bill.getBillBelong());
                  if (Objects.isNull(target)) {
                      return co;
                  }

                  co.setTarget(new TeamMemberWorkTargetCO()
                          .setId(target.getTimeId())
                          .setAcceptGiftValue(target.sumAcceptGiftValue())
                          .setAcceptGiftValueFormat(NumUtils.formatLong(target.sumAcceptGiftValue()))
                          .setOnlineTime(target.sumAllTargetTime())
                          .setEffectiveDay(TeamBillCycleUtils.calculateEffectiveDay(target))
                          .setDailyTargets(target.getDailyTargets().stream()
                                  .filter(dailyTarget -> dailyTarget.getDateNumber()
                                          <= ZonedDateTimeAsiaRiyadhUtils.nowDateToInt())
                                  .map(dailyTarget -> new TeamMemberWorkDailyTargetCO()
                                          .setOnlineTime(dailyTarget.allOnlineTime())
                                          .setAcceptGiftValue(dailyTarget.getAcceptGiftValue())
                                          .setDateNumber(dailyTarget.getDateNumber())
                                          .setCreateTime(dailyTarget.getCreateTime())
                                  )
                                  .sorted(Comparator.comparing(TeamMemberWorkDailyTargetCO::getDateNumber,
                                          Comparator.reverseOrder()))
                                  .collect(Collectors.toList()))
                          .setSettlementResult(teamAppConvertor.toTeamMemberTargetSettlementResultCO(
                                  target.getSettlementResult()))
                  );

                  if (Objects.nonNull(target.getSettlementResult()) && !Objects.equals(bill.getStatus(),
                          TeamBillCycleStatus.UNPAID)) {
                      return co;
                  }

                  // 使用 target 自身的 region 和 countryCode 查找匹配的 policy
                  TeamPolicyManager policy = TeamBillCycleUtils.getPolicyFromMap(
                      regionPolicy,
                      target.getRegion(),
                      target.getCountryCode());
                  
                  if (Objects.isNull(policy)) {
                      return co;
                  }

                  TeamBillMemberTarget teamBillMemberTarget = TeamBillCycleUtils.calculatorPolicyTarget(target, policy);
                  co.getTarget().setSettlementResult(
                          teamAppConvertor.toTeamMemberTargetSettlementResultCO(teamBillMemberTarget)
                  );
                  return co;
              }).collect(Collectors.toList())
      )
      .setHistorySalary(settledAndSumSalary);
    return teamMemberWorkCO;
  }

    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");
    }

  private TeamBillMemberTarget calculatorTarget(TeamMemberTarget target,
      TeamPolicyManager policy) {

    if (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 TeamBillMemberTarget calculatorDiamondTarget(TeamMemberTarget target,
                                                  TeamPolicyManager policy, Integer billBelongDay) {
        BillDiamondBalanceDetails billDiamondBalance = billDiamondBalanceDetailsService.getEntityByBillBelongAndUserIdAndBillBelongDay(target.getSysOrigin(), target.getUserId(), billBelongDay);
        return TeamBillCycleUtils.calculatorPolicyDiamondTarget(target, policy, Objects.nonNull(billDiamondBalance) ? billDiamondBalance.getConsumptionPoints() : BigDecimal.ZERO);
    }

}
