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

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.red.circle.common.business.dto.cmd.app.RecommendCmd;
import com.red.circle.framework.core.dto.CommonCommand;
import com.red.circle.other.app.command.user.query.UserRelationFollowQryExe;
import com.red.circle.other.app.dto.clientobject.home.RecommendUserCO;
import com.red.circle.other.app.dto.clientobject.home.RecommendUserProfileCO;
import com.red.circle.other.app.service.user.user.UserProfileService;
import com.red.circle.other.app.service.user.user.UserRegionService;
import com.red.circle.other.app.service.user.user.UserRegionServiceImpl;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.UserRunProfileTransportGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
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.ActiveVoiceRoom;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.entity.user.status.OnlineUser;
import com.red.circle.other.infra.database.mongo.service.activity.RankCountService;
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.user.status.OnlineUserService;
import com.red.circle.other.infra.database.rds.entity.user.user.RelationshipFriend;
import com.red.circle.other.infra.database.rds.entity.user.user.UserExpand;
import com.red.circle.other.infra.database.rds.entity.user.user.UserSubscription;
import com.red.circle.other.infra.database.rds.service.user.user.ExpandService;
import com.red.circle.other.infra.database.rds.service.user.user.RelationshipFriendService;
import com.red.circle.other.infra.database.rds.service.user.user.UserSubscriptionService;
import com.red.circle.other.inner.model.cmd.live.AppActiveVoiceRoomQryCmd;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.text.StringPool;
import com.red.circle.tool.core.text.StringUtils;
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.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 首页在线用户
 *
 * @author zongpubin on 2023/12/5
 */
@Slf4j
@Component
@AllArgsConstructor
public class RecommendUserQueryExe {

  private final ExpandService expandService;
  private final RankCountService rankCountService;
  private final OnlineUserService onlineUserService;
  private final UserProfileService userProfileService;
  private final ActiveVoiceRoomService activeVoiceRoomService;
  private final UserSubscriptionService userSubscriptionService;
  private final RelationshipFriendService relationshipFriendService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final UserRunProfileTransportGateway userRunProfileTransportGateway;
  private final UserRegionGateway userRegionGateway;

  public RecommendUserCO execute(RecommendCmd cmd) {
    Set<Long> userIds = Sets.newHashSet();
    List<RecommendUserProfileCO> followUserProfiles = Lists.newArrayList();
    List<RecommendUserProfileCO> recommendUserProfiles = Lists.newArrayList();

    // 用户关注列表
    Set<Long> userSubscriptions = userSubscriptionService.listByUserId(
            cmd.getReqUserId(),null, null).stream().map(UserSubscription::getSubscribeUserId)
        .collect(Collectors.toSet());
    userIds.addAll(userSubscriptions);
    // 用户好友列表
    Set<Long> relationshipFriends = relationshipFriendService.flowSize1000(
        cmd.getReqUserId(), null,null).stream().map(RelationshipFriend::getFriendUserId).collect(
        Collectors.toSet());
    userIds.addAll(relationshipFriends);

    // 用户个性签名
    Map<Long, UserExpand> expandMap = expandService.mapExpand(userIds);

    List<OnlineUser> onlineUsers = onlineUserService.userOnlineByUserIds(userIds);
    if (CollectionUtils.isNotEmpty(onlineUsers)) {
      for (OnlineUser onlineUser : onlineUsers){
        if (StringUtils.isNotBlank(onlineUser.getUserNickname()) && StringUtils.isNotBlank(onlineUser.getUserAvatar())){
          followUserProfiles.add(RecommendUserProfileCO.builder()
                  .id(onlineUser.getUserId())
                  .userAvatar(onlineUser.getUserAvatar())
                  .userNickname(onlineUser.getUserNickname())
                  .userSex(onlineUser.getGender())
                  .roomId(onlineUser.getSessionId())
                  .signature(Optional.ofNullable(expandMap.get(onlineUser.getUserId()))
                          .map(UserExpand::getSignature)
                          .orElse(StringPool.EMPTY))
                  .build());
        }
      }
//      followUserProfiles.addAll(onlineUsers.stream().map(onlineUser ->
//          RecommendUserProfileCO.builder()
//              .id(onlineUser.getUserId())
//              .userAvatar(onlineUser.getUserAvatar())
//              .userNickname(onlineUser.getUserNickname())
//              .userSex(onlineUser.getGender())
//              .roomId(onlineUser.getSessionId())
//              .signature(Optional.ofNullable(expandMap.get(onlineUser.getUserId()))
//                  .map(UserExpand::getSignature)
//                  .orElse(StringPool.EMPTY))
//              .build()).collect(Collectors.toList()));
    }

    if (userIds.size() >= 100) {
      List<RecommendUserProfileCO> followUsers = followUserProfiles.stream().limit(100)
          .collect(Collectors.toList());
      if (StringUtils.isNotBlank(cmd.getAccount())) {
        UserProfileDTO userProfile = userProfileService.getByAccount(cmd.getReqSysOrigin().getOrigin(),
            cmd.getAccount());

        if (Objects.nonNull(userProfile)) {
          String sessionId = onlineUserService.getSessionId(userProfile.getId());
          if (Objects.nonNull(sessionId)) {
            RoomProfile roomProfile = roomProfileManagerService.getProfileById(Long.valueOf(sessionId));
            if (Objects.isNull(roomProfile)) {
              return RecommendUserCO.builder()
                  .followUserProfiles(Lists.newArrayList())
                  .recommendUserProfiles(Lists.newArrayList())
                  .build();
            }

            List<RecommendUserProfileCO> filterFollowUsers = followUsers.stream()
                .filter(profile -> profile.getRoomId() != null && profile.getRoomId()
                    .equals(roomProfile.getId()))
                .collect(Collectors.toList());
            return RecommendUserCO.builder()
                .followUserProfiles(filterFollowUsers)
                .recommendUserProfiles(Lists.newArrayList())
                .build();
          }


        }

      }

      return RecommendUserCO.builder()
          .followUserProfiles(followUsers)
          .recommendUserProfiles(recommendUserProfiles)
          .build();
    }

    if (StringUtils.isNotBlank(cmd.getAccount())) {
      UserProfileDTO userProfile = userProfileService.getByAccount(cmd.requireReqSysOrigin(),
          cmd.getAccount());

      if (Objects.nonNull(userProfile)) {
        String sessionId = onlineUserService.getSessionId(userProfile.getId());
        if (Objects.nonNull(sessionId)) {
          RoomProfile roomProfile = roomProfileManagerService.getProfileById(Long.valueOf(sessionId));
          if (Objects.isNull(roomProfile)) {
            return RecommendUserCO.builder()
                .followUserProfiles(Lists.newArrayList())
                .recommendUserProfiles(Lists.newArrayList())
                .build();
          }

          List<RecommendUserProfileCO> filterFollowUsers = followUserProfiles.stream()
              .filter(profile -> profile.getRoomId() != null && profile.getRoomId()
                  .equals(roomProfile.getId()))
              .collect(Collectors.toList());
          if (CollectionUtils.isNotEmpty(filterFollowUsers)) {
            return RecommendUserCO.builder()
                .followUserProfiles(filterFollowUsers)
                .recommendUserProfiles(Lists.newArrayList())
                .build();
          }

        }


      } else {
        return RecommendUserCO.builder()
            .followUserProfiles(Lists.newArrayList())
            .recommendUserProfiles(Lists.newArrayList())
            .build();
      }

    }

    // 推荐用户列表
    List<OnlineUser> recommendUsers = recommendUser(cmd, userIds);

    Map<Long, UserExpand> recommendExpandMap = expandService.mapExpand(
        recommendUsers.stream().map(OnlineUser::getUserId).collect(
            Collectors.toSet()));
    if ((100 - userIds.size()) < recommendUsers.size()) {
      recommendUsers = recommendUsers.stream().limit((100 - userIds.size()))
          .collect(Collectors.toList());
    }
    if (CollectionUtils.isNotEmpty(recommendUsers)) {
      for (OnlineUser onlineUser : recommendUsers){
        if (StringUtils.isNotBlank(onlineUser.getUserNickname()) && StringUtils.isNotBlank(onlineUser.getUserAvatar())){
          recommendUserProfiles.add(RecommendUserProfileCO.builder()
                  .id(onlineUser.getUserId())
                  .userAvatar(onlineUser.getUserAvatar())
                  .userNickname(onlineUser.getUserNickname())
                  .userSex(onlineUser.getGender())
                  .roomId(onlineUser.getSessionId())
                  .signature(Optional.ofNullable(recommendExpandMap.get(onlineUser.getUserId()))
                          .map(UserExpand::getSignature)
                          .orElse(StringPool.EMPTY))
                  .build());
        }
      }
//      recommendUserProfiles.addAll(recommendUsers.stream().map(recommendOnlineUser ->
//          RecommendUserProfileCO.builder()
//              .id(recommendOnlineUser.getUserId())
//              .userAvatar(recommendOnlineUser.getUserAvatar())
//              .userNickname(recommendOnlineUser.getUserNickname())
//              .userSex(recommendOnlineUser.getGender())
//              .roomId(recommendOnlineUser.getSessionId())
//              .signature(
//                  Optional.ofNullable(recommendExpandMap.get(recommendOnlineUser.getUserId()))
//                      .map(UserExpand::getSignature)
//                      .orElse(StringPool.EMPTY))
//              .build()).collect(Collectors.toList()));
    }

    if (StringUtils.isNotBlank(cmd.getAccount())) {
      UserProfileDTO userProfile = userProfileService.getByAccount(cmd.getReqSysOrigin().getOrigin(),
          cmd.getAccount());

      if (Objects.nonNull(userProfile)) {
        String sessionId = onlineUserService.getSessionId(userProfile.getId());
        if (Objects.nonNull(sessionId)) {
          RoomProfile roomProfile = roomProfileManagerService.getProfileById(Long.valueOf(sessionId));
          if (Objects.isNull(roomProfile)) {
            return RecommendUserCO.builder()
                .followUserProfiles(Lists.newArrayList())
                .recommendUserProfiles(Lists.newArrayList())
                .build();
          }

          List<RecommendUserProfileCO> filterRecommendUserProfiles = recommendUserProfiles.stream()
              .filter(profile -> profile.getRoomId() != null && profile.getRoomId()
                  .equals(roomProfile.getId()))
              .collect(Collectors.toList());
          return RecommendUserCO.builder()
              .followUserProfiles(Lists.newArrayList())
              .recommendUserProfiles(filterRecommendUserProfiles)
              .build();
        }


      } else {
        return RecommendUserCO.builder()
            .followUserProfiles(Lists.newArrayList())
            .recommendUserProfiles(Lists.newArrayList())
            .build();
      }

    }

    return RecommendUserCO.builder()
        .followUserProfiles(followUserProfiles)
        .recommendUserProfiles(recommendUserProfiles)
        .build();
  }

  private List<OnlineUser> recommendUser(RecommendCmd cmd, Set<Long> followUsers) {
    List<OnlineUser> userIds = Lists.newArrayList();
    List<Long> roomIds = Lists.newArrayList();
    String roomOwnRegionCode = userRegionGateway.getRegionCode(cmd.requiredReqUserId());
    String region =
        (Objects.equals(roomOwnRegionCode, "TR") || Objects.equals(roomOwnRegionCode, "AR"))
            ? roomOwnRegionCode : "OTHER";
    if (Objects.equals(region, "OTHER")) {
      UserProfile userProfile = userRunProfileTransportGateway.getByUserId(cmd.requiredReqUserId());
      AppActiveVoiceRoomQryCmd appActiveVoiceRoomQryCmd =  new AppActiveVoiceRoomQryCmd();
      appActiveVoiceRoomQryCmd.setCountryCode(userProfile.getCountryCode());
      appActiveVoiceRoomQryCmd.setSysOrigin(cmd.requireReqSysOrigin());
      appActiveVoiceRoomQryCmd.setLimit(300);
      roomIds = activeVoiceRoomService
          .listExcludeCountry(appActiveVoiceRoomQryCmd).stream().map(ActiveVoiceRoom::getId).collect(Collectors.toList());
      if (CollectionUtils.isEmpty(roomIds)) {
        return Lists.newArrayList();
      }
      for (Long roomId : roomIds) {
        List<OnlineUser> onlineUsers = onlineUserService.flowLanguageHallByRoomId(roomId);
        if (CollectionUtils.isNotEmpty(onlineUsers)) {
          if (!followUsers.contains(onlineUsers.get(0).getUserId())) {
            userIds.add(onlineUsers.get(0));
          }
        }
      }

    } else {
      List<RankQueenCount> rankQueenCounts = rankCountService.listRank(cmd.requireReqSysOrigin(),
          RankQueenType.ROOM_RANK_DAY, 500);
      roomIds = getRoomIds(rankQueenCounts);

      if (CollectionUtils.isEmpty(roomIds)) {
        return Lists.newArrayList();
      }
      for (Long roomId : roomIds) {
        List<OnlineUser> onlineUsers = onlineUserService.flowLanguageHallByRoomId(roomId);
        if (CollectionUtils.isNotEmpty(onlineUsers)) {
          if (!followUsers.contains(onlineUsers.get(0).getUserId())) {
            userIds.add(onlineUsers.get(0));
          }
        }
      }
    }
    return userIds;

  }

  private List<Long> getRoomIds(List<RankQueenCount> days) {
    return days.stream().map(RankQueenCount::getBusinessId).collect(Collectors.toList());
  }
}
