package com.red.circle.console.app.service.app.game;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.red.circle.console.app.dto.clienobject.game.GameRedPacketCO;
import com.red.circle.console.app.dto.clienobject.game.GameRedPacketReceiveUsersCO;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.inner.endpoint.game.GameRedPacketBackClient;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.enums.game.RedPacketEnum;
import com.red.circle.other.inner.model.cmd.game.GameRedPacketBackQryCmd;
import com.red.circle.other.inner.model.dto.game.GameRedPacketDTO;
import com.red.circle.other.inner.model.dto.game.GameRedPacketReceiveUsersDTO;
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
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;

/**
 * 红包发送记录
 *
 * @author zongpubin on 2024/1/27
 */
@Service
@RequiredArgsConstructor
public class GameRedPacketBackServiceImpl implements GameRedPacketBackService {

  private final RoomManagerClient roomManagerClient;
  private final UserProfileClient userProfileClient;
  private final GameRedPacketBackClient gameRedPacketBackClient;

  @Override
  public List<GameRedPacketCO> listGameRedPacket(GameRedPacketBackQryCmd query) {

    List<GameRedPacketDTO> gameRedPackets = ResponseAssert.requiredSuccess(
        gameRedPacketBackClient.listGameRedPacket(query));

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

    Map<Long, RoomProfileDTO> roomProfileMap = getRoomProfileMap(query, gameRedPackets);

    Map<Long, UserProfileDTO> userProfileMap = ResponseAssert.requiredSuccess(
        userProfileClient.mapByUserIds(
            getAllUserIds(query, gameRedPackets)));

    return gameRedPackets.stream().map(gameRedPacket -> {
      GameRedPacketCO vo = new GameRedPacketCO();
      vo.setId(gameRedPacket.getId());
      vo.setLogs(gameRedPacket.getLogs());
      vo.setAmount(gameRedPacket.getAmount());
      vo.setQuantity(gameRedPacket.getQuantity());
      vo.setExpiredTime(gameRedPacket.getExpiredTime());
      vo.setSysOrigin(gameRedPacket.getSysOrigin());
      vo.setUpdateTime(gameRedPacket.getUpdateTime());
      vo.setRelationId(gameRedPacket.getRelationId());
      vo.setCreateTime(gameRedPacket.getCreateTime());
      vo.setReceivedAmount(gameRedPacket.sumReceiveAmount());
      vo.setStatus(gameRedPacket.getStatus());
      vo.setReceiveUsers(gameRedPacket.getReceiveUsers().stream()
          .map(gameRedPacketUsers -> new GameRedPacketReceiveUsersCO().setUserId(
                  gameRedPacketUsers.getUserId()).setAmount(gameRedPacketUsers.getAmount())
              .setCreateTime(gameRedPacketUsers.getCreateTime())).collect(Collectors.toList()));
      vo.setType(StringUtils.isNotBlank(gameRedPacket.getType()) ? RedPacketEnum
          .valueOf(gameRedPacket.getType()) : RedPacketEnum.ROOM);

      if (Objects.equals(vo.getType(), RedPacketEnum.ROOM)) {
        vo.setRoomProfile(roomProfileMap.get(
            Objects.isNull(gameRedPacket.getRoomId()) ? gameRedPacket.getRelationId()
                : gameRedPacket.getRoomId()));
      }

      if (Objects.equals(vo.getType(), RedPacketEnum.USER) && Objects
          .nonNull(gameRedPacket.getReceiverId())) {

        vo.setDesignatedReceiverUser(userProfileMap.get(gameRedPacket.getReceiverId()));
      }

      vo.setUserProfile(userProfileMap.get(gameRedPacket.getUserId()));

      if (CollectionUtils.isEmpty(vo.getReceiveUsers())) {
        return vo;
      }

      vo.setReceiveUsers(vo.getReceiveUsers().stream().peek(
              receiveUser -> receiveUser.setUserProfile(userProfileMap.get(receiveUser.getUserId())))
          .collect(Collectors.toList()));
      return vo;
    }).collect(Collectors.toList());
  }

  private Map<Long, RoomProfileDTO> getRoomProfileMap(GameRedPacketBackQryCmd query,
      List<GameRedPacketDTO> gameRedPackets) {

    if (Objects.equals(query.getType(), RedPacketEnum.ROOM) || Objects.isNull(query.getType())) {

      return ResponseAssert.requiredSuccess(roomManagerClient.mapProfileByRoomIds(
          gameRedPackets.stream().map(gameRedPacket -> {
                if (Objects.nonNull(gameRedPacket.getRoomId())) {
                  return gameRedPacket.getRoomId();
                }
                if (Objects.nonNull(gameRedPacket.getRelationId())) {
                  return gameRedPacket.getRelationId();
                }
                return null;
              })
              .filter(Objects::nonNull)
              .collect(Collectors.toSet())));
    }
    return Maps.newHashMap();
  }

  private Set<Long> getAllUserIds(GameRedPacketBackQryCmd query,
      List<GameRedPacketDTO> gameRedPackets) {

    Set<Long> sendUserIds = gameRedPackets.stream().map(GameRedPacketDTO::getUserId)
        .collect(Collectors.toSet());

    Set<Long> receiveUserIds = gameRedPackets.stream().map(GameRedPacketDTO::getReceiveUsers)
        .filter(CollectionUtils::isNotEmpty)
        .flatMap(Collection::stream)
        .map(GameRedPacketReceiveUsersDTO::getUserId)
        .collect(Collectors.toSet());

    // 查询1v1用户
    if (Objects.equals(query.getType(), RedPacketEnum.USER)) {
      sendUserIds.addAll(gameRedPackets.stream().map(GameRedPacketDTO::getRelationId)
          .filter(Objects::nonNull).collect(Collectors.toSet()));
      sendUserIds.addAll(gameRedPackets.stream().map(GameRedPacketDTO::getReceiverId)
          .filter(Objects::nonNull).collect(Collectors.toSet()));
    }

    if (CollectionUtils.isEmpty(receiveUserIds)) {
      return sendUserIds;
    }

    receiveUserIds.addAll(sendUserIds);
    return receiveUserIds;
  }
}
