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

import com.google.common.collect.Lists;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.other.infra.common.user.UserCpUtils;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.activity.ActivityCpUserRankingCO;
import com.red.circle.other.app.dto.clientobject.activity.ActivityWeekCpGiftCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.mongo.entity.user.count.WeekCpValueCount;
import com.red.circle.other.infra.database.mongo.service.user.count.WeekCpValueCountService;
import com.red.circle.other.infra.database.rds.entity.user.user.CpRelationship;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.model.dto.user.WeekCpUserIdDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 每周CP用户礼物护送消耗.
 *
 * @author pengshigang on 2021/08/28
 * @since pengliang on 2022-03-25
 */
@Service
@RequiredArgsConstructor
public class WeekCpUserGiftQueryExe {

  private final UserRegionGateway userRegionGateway;
  private final UserProfileGateway userProfileGateway;
  private final CpRelationshipService cpRelationshipService;
  private final WeekCpValueCountService weekCpValueCountService;
  private final UserProfileAppConvertor userProfileAppConvertor;

  public ActivityWeekCpGiftCO execute(AppExtCommand cmd) {
    return new ActivityWeekCpGiftCO()
        .setThisWeekUserTop(getThisWeekUser(cmd))
        .setLastWeekUserTop(getLastWeekUser(cmd))
        .setThisUser(getThisUser(cmd));
  }

  private List<ActivityCpUserRankingCO> fill(AppExtCommand cmd,
      List<ActivityCpUserRankingCO> rankings) {
    int resultSize = 20;
    if (CollectionUtils.isEmpty(rankings)) {
      return assembleFill(cpRelationshipService.listLatestCp(
              cmd.getReqSysOrigin().getOrigin(), resultSize
          )
      );
    }

    if (rankings.size() >= resultSize) {
      return rankings;
    }

    int fillSize = resultSize - rankings.size();
    List<ActivityCpUserRankingCO> fillCo = assembleFill(
        cpRelationshipService.listLatestCp(
            cmd.getReqSysOrigin().getOrigin(),
            getAllUserIds(rankings),
            fillSize
        )
    );
    if (CollectionUtils.isEmpty(fillCo)) {
      return rankings;
    }
    rankings.addAll(fillCo);
    return rankings;
  }

  private List<ActivityCpUserRankingCO> assembleFill(
      List<CpRelationship> cpRelationships) {
    if (CollectionUtils.isEmpty(cpRelationships)) {
      return Lists.newArrayList();
    }
    Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(
            cpRelationships.stream().map(
                cpRelationship -> Arrays.asList(cpRelationship.getUserId(),
                    cpRelationship.getCpUserId())
            ).flatMap(Collection::stream).collect(Collectors.toSet())));

    return cpRelationships.stream().map(cpRelationship -> {
          UserProfileDTO userProfile = userProfileMap.get(cpRelationship.getUserId());
          UserProfileDTO cpUserProfile = userProfileMap.get(cpRelationship.getCpUserId());
          if (Objects.isNull(userProfile) || Objects.isNull(cpUserProfile)) {
            return null;
          }
          return new ActivityCpUserRankingCO()
              .setUserId(userProfile.getId())
              .setUserAvatar(userProfile.getUserAvatar())
              .setUserNickname(userProfile.getUserNickname())
              .setUserSex(userProfile.getUserSex())
              .setTotalNumber(0L)
              .setTotal("0")
              .setCpUserId(cpUserProfile.getId())
              .setCpUserAvatar(cpUserProfile.getUserAvatar())
              .setCpUserNickname(cpUserProfile.getUserNickname())
              .setCpUserSex(cpUserProfile.getUserSex())
              .setUserProfiles(List.of(userProfile,
                  cpUserProfile));
        }).filter(Objects::nonNull)
        .toList();
  }

  private ActivityCpUserRankingCO getThisUser(AppExtCommand cmd) {

    List<Long> cpUserIdList = cpRelationshipService.getCpUserId(cmd.getReqUserId());
    if (cpUserIdList.isEmpty()) {
      return new ActivityCpUserRankingCO();
    }

      Long cpUserId = cpUserIdList.get(0);
      WeekCpValueCount thisUser = weekCpValueCountService.getUserThisWeekCount(
        cmd.getReqSysOrigin().getOrigin(),
        cmd.getReqUserId(), cpUserId);
    if (Objects.isNull(thisUser)) {
      return new ActivityCpUserRankingCO();
    }
    List<ActivityCpUserRankingCO> users = assemble(Lists.newArrayList(thisUser));
    if (CollectionUtils.isEmpty(users)) {
      return new ActivityCpUserRankingCO();
    }
    return users.get(0);
  }

  private List<ActivityCpUserRankingCO> getThisWeekUser(AppExtCommand cmd) {
    return assemble(weekCpValueCountService.listThisWeekTop(
        cmd.getReqSysOrigin().getOrigin(),
        userRegionGateway.getRegionCode(cmd.getReqUserId()),
        20)
    );
  }

  private List<ActivityCpUserRankingCO> getLastWeekUser(AppExtCommand cmd) {
    return assemble(weekCpValueCountService.listLastWeekTop(
        cmd.getReqSysOrigin().getOrigin(),
        userRegionGateway.getRegionCode(cmd.getReqUserId()),
        3)
    );
  }

  private List<ActivityCpUserRankingCO> assemble(List<WeekCpValueCount> weekCpValueCounts) {
    if (CollectionUtils.isEmpty(weekCpValueCounts)) {
      return Lists.newArrayList();
    }

    List<ActivityCpUserRankingCO> results = weekCpValueCounts.stream().map(weekCpValueCount -> {
          WeekCpUserIdDTO userIdPair = UserCpUtils.parseUserIdPair(weekCpValueCount.getId());
          return new ActivityCpUserRankingCO()
              .setUserId(userIdPair.getUserIdOne())
              .setCpUserId(userIdPair.getUserIdTwo())
              .setTotalNumber(weekCpValueCount.getQuantity())
              .setTotal(NumUtils.formatLong(weekCpValueCount.getQuantity()));
        }
    ).toList();

    Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
        userProfileGateway.mapByUserIds(
            getAllUserIds(results))
    );

    return results.stream().map(ranking -> {
          UserProfileDTO userProfile = userProfileMap.get(ranking.getUserId());
          UserProfileDTO cpUserProfile = userProfileMap.get(ranking.getCpUserId());
          if (Objects.isNull(userProfile) || Objects.isNull(cpUserProfile)) {
            return null;
          }
          ranking.setUserAvatar(userProfile.getUserAvatar());
          ranking.setUserNickname(userProfile.getUserNickname());
          ranking.setUserSex(userProfile.getUserSex());

          ranking.setCpUserAvatar(cpUserProfile.getUserAvatar());
          ranking.setCpUserNickname(cpUserProfile.getUserNickname());
          ranking.setCpUserSex(cpUserProfile.getUserSex());
          ranking.setUserProfiles(List.of(userProfile,
              cpUserProfile));
          return ranking;
        })
        .filter(Objects::nonNull)
        .toList();
  }

  private Set<Long> getAllUserIds(List<ActivityCpUserRankingCO> results) {
    return results.stream()
        .map(ranking -> Arrays.asList(ranking.getUserId(), ranking.getCpUserId()))
        .flatMap(Collection::stream)
        .collect(Collectors.toSet());
  }


}
