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

import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.other.app.dto.clientobject.activity.ActivityLeaderboardCO;
import com.red.circle.other.app.dto.clientobject.activity.ActivityLeaderboardCO.LeaderboardUserCO;
import com.red.circle.other.domain.enums.VipAbilityType;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenCount;
import com.red.circle.other.infra.database.mongo.entity.activity.RankQueenType;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.service.activity.RankCountService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.utils.UserIdEncryptUtils;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.num.NumUtils;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 房间礼物排行榜.
 *
 * @author pengliang on 2021/2/24
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoomGiftsLeaderboardQryExe {

  private final RankCountService rankCountService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final UserProfileGateway userProfileGateway;
  private final EnumConfigCacheService enumConfigCacheService;

  public ActivityLeaderboardCO execute(AppExtCommand cmd) {
    List<RankQueenCount> hours = getListRank(cmd, RankQueenType.ROOM_RANK_HOUR,50);
    List<RankQueenCount> days = getListRank(cmd, RankQueenType.ROOM_RANK_DAY,50);
    List<RankQueenCount> weeks = getListRank(cmd, RankQueenType.ROOM_RANK_WEEK,50);
    List<RankQueenCount> months = getListRank(cmd, RankQueenType.ROOM_RANK_MONTH,50);

    Set<Long> roomIds = getAllUserIds(days, weeks, months, hours);
    if (CollectionUtils.isEmpty(roomIds)) {
      return ActivityLeaderboardCO.empty();
    }
    Map<Long, RoomProfile> roomProfileMap = roomProfileManagerService.mapProfileByRoomIds(roomIds);
    Set<Long> ownerIds = roomProfileMap.values().stream()
            .map(RoomProfile::getUserId).filter(Objects::nonNull).collect(Collectors.toSet());
    Set<Long> invisibleOwnerIds = userProfileGateway.filterUsersByVipAbility(ownerIds, VipAbilityType.MYSTERIOUS_INVISIBILITY);

    return new ActivityLeaderboardCO()
        .setHourly(toLeaderboardUserCO(hours, roomProfileMap, invisibleOwnerIds))
        .setDaily(toLeaderboardUserCO(days, roomProfileMap, invisibleOwnerIds))
        .setWeekly(toLeaderboardUserCO(weeks, roomProfileMap, invisibleOwnerIds))
        .setMonthly(toLeaderboardUserCO(months, roomProfileMap, invisibleOwnerIds));
  }

  public ActivityLeaderboardCO executeApp(AppExtCommand cmd) {

//    List<RankQueenCount> days = getListRank(cmd, RankQueenType.ROOM_RANK_DAY,3);
    List<RankQueenCount> weeks = getListRank(cmd, RankQueenType.ROOM_RANK_WEEK,3);
//    List<RankQueenCount> months = getListRank(cmd, RankQueenType.ROOM_RANK_MONTH,3);

    Set<Long> roomIds = getAllUserIds(null, weeks, null);
    if (CollectionUtils.isEmpty(roomIds)) {
      return ActivityLeaderboardCO.empty();
    }
    Map<Long, RoomProfile> roomProfileMap = roomProfileManagerService.mapProfileByRoomIds(roomIds);
    Set<Long> ownerIds = roomProfileMap.values().stream()
            .map(RoomProfile::getUserId).filter(Objects::nonNull).collect(Collectors.toSet());
    Set<Long> invisibleOwnerIds = userProfileGateway.filterUsersByVipAbility(ownerIds, VipAbilityType.MYSTERIOUS_INVISIBILITY);

    return new ActivityLeaderboardCO()
            .setDaily(toLeaderboardUserCO(null, roomProfileMap, invisibleOwnerIds))
            .setWeekly(toLeaderboardUserCO(weeks, roomProfileMap, invisibleOwnerIds))
            .setMonthly(toLeaderboardUserCO(null, roomProfileMap, invisibleOwnerIds));
  }

  private Set<Long> getAllUserIds(List<RankQueenCount> days, List<RankQueenCount> weeks,
      List<RankQueenCount> months) {
    Set<Long> roomIds = getRoomIds(days);
    roomIds.addAll(getRoomIds(weeks));
    roomIds.addAll(getRoomIds(months));
    return roomIds;
  }

  private Set<Long> getAllUserIds(List<RankQueenCount> days, List<RankQueenCount> weeks,
                                  List<RankQueenCount> months, List<RankQueenCount> hours) {
    Set<Long> roomIds = getRoomIds(days);
    roomIds.addAll(getRoomIds(weeks));
    roomIds.addAll(getRoomIds(months));
    roomIds.addAll(getRoomIds(hours));
    return roomIds;
  }

  private List<LeaderboardUserCO> toLeaderboardUserCO(List<RankQueenCount> list,
      Map<Long, RoomProfile> roomProfileMap, Set<Long> invisibleOwnerIds) {

    if (CollectionUtils.isEmpty(list)) {
      return CollectionUtils.newArrayList();
    }
    return list.stream().map(count -> {
      RoomProfile roomProfile = roomProfileMap.get(count.getBusinessId());
      if (Objects.isNull(roomProfile)) {
        log.warn("数据异常,找不到房间记录: {}", JacksonUtils.toJson(count));
        return null;
      }
      LeaderboardUserCO co = new LeaderboardUserCO()
          .setQuantity(count.getQuantity())
          .setQuantityFormat(NumUtils.formatLong(count.getQuantity()));
      if (Objects.nonNull(roomProfile.getUserId()) && invisibleOwnerIds.contains(roomProfile.getUserId())) {
        co.setId(null);
        co.setEncryptedId(UserIdEncryptUtils.encrypt(roomProfile.getId()));
        co.setNickname("****");
        co.setAvatar(enumConfigCacheService.getValue(EnumConfigKey.USER_YINSHEN_COVER, roomProfile.getSysOrigin()));
      } else {
        co.setId(roomProfile.getId());
        co.setAvatar(roomProfile.getRoomCover());
        co.setNickname(roomProfile.getRoomName());
      }
      return co;
    }).filter(Objects::nonNull).collect(Collectors.toList());
  }

  private Set<Long> getRoomIds(List<RankQueenCount> counts) {
    if (CollectionUtils.isEmpty(counts)) {
      return CollectionUtils.newHashSet();
    }
    return counts.stream().map(RankQueenCount::getBusinessId).collect(Collectors.toSet());
  }

  private List<RankQueenCount> getListRank(AppExtCommand cmd, RankQueenType charmRankDay ,Integer size) {
    return Optional
        .ofNullable(rankCountService.listRank(cmd.requireReqSysOrigin(), charmRankDay, size))
        .orElseGet(CollectionUtils::newArrayList);
  }

}
