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

import com.google.common.collect.Lists;
import com.red.circle.console.app.dto.clienobject.game.GameRoomPkCO;
import com.red.circle.console.app.dto.clienobject.game.GameTeamPkCO;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.inner.endpoint.game.GamePkClient;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.model.cmd.game.GameRoomPkRecordQryCmd;
import com.red.circle.other.inner.model.cmd.game.GameTeamPkRecordQryCmd;
import com.red.circle.other.inner.model.dto.game.GameRoomPkCountDTO;
import com.red.circle.other.inner.model.dto.game.GameTeamPkCountDTO;
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
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.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * Game PK
 *
 * @author zongpubin on 2024/1/27
 */
@Service
@RequiredArgsConstructor
public class GamePkServiceImpl implements GamePkService {

  private final GamePkClient gamePkClient;
  private final RoomManagerClient roomManagerClient;
  private final UserProfileClient userProfileClient;

  @Override
  public List<GameRoomPkCO> listRoomPk(GameRoomPkRecordQryCmd query) {
    List<GameRoomPkCountDTO> roomPkCounts = ResponseAssert.requiredSuccess(
        gamePkClient.listRoomPk(query));

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

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

    Map<Long, UserProfileDTO> userProfileMap = getUserProfileMap(roomPkCounts);

    return roomPkCounts.stream().map(count -> {
      GameRoomPkCO vo = new GameRoomPkCO()
          .setId(count.getId())
          .setSysOrigin(count.getSysOrigin())
          .setPkType(count.getPkType())
          .setRecipientIntegral(Optional.ofNullable(count.getRecipientIntegral()).orElse(0L))
          .setSponsorIntegral(Optional.ofNullable(count.getSponsorIntegral()).orElse(0L))
          .setCreateTime(count.getCreateTime());

      vo.setRecipientRoomProfile(roomProfileMap.get(count.getRecipientRoomId()));
      vo.setSponsorRoomProfile(roomProfileMap.get(count.getSponsorRoomId()));
      vo.setRecipientUserProfile(userProfileMap.get(count.getRecipientUserId()));
      vo.setSponsorUserProfile(userProfileMap.get(count.getSponsorUserId()));
      return vo;
    }).collect(Collectors.toList());
  }


  private Map<Long, UserProfileDTO> getUserProfileMap(List<GameRoomPkCountDTO> gameRoomPkCounts) {
    return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(
        gameRoomPkCounts.stream()
            .map(count -> List.of(count.getRecipientUserId(), count.getSponsorUserId()))
            .flatMap(Collection::stream)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet())));
  }

  private Map<Long, RoomProfileDTO> getRoomProfileMap(List<GameRoomPkCountDTO> gameRoomPkCounts) {
    return ResponseAssert.requiredSuccess(roomManagerClient.mapProfileByRoomIds(
        gameRoomPkCounts.stream()
            .map(count -> List.of(count.getRecipientRoomId(), count.getSponsorRoomId()))
            .flatMap(Collection::stream)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet())));
  }

  @Override
  public List<GameTeamPkCO> listTeamPk(GameTeamPkRecordQryCmd query) {
    List<GameTeamPkCountDTO> teamPkCounts = ResponseAssert.requiredSuccess(
        gamePkClient.listTeamPk(query));

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

    Map<Long, UserProfileDTO> userProfileMap = getProfileMap(teamPkCounts);

    Map<Long, RoomProfileDTO> roomProfileMap = getRoomMap(teamPkCounts);

    return teamPkCounts.stream().map(count -> new GameTeamPkCO()
        .setId(count.getId())
        .setSysOrigin(count.getSysOrigin())
        .setMsvUserProfile(userProfileMap.get(count.getMvpUserId()))
        .setRoomProfile(roomProfileMap.get(count.getRoomId()))
        .setBlueTeamScore(Optional.ofNullable(count.getBlueTeamScore()).orElse(0L))
        .setRedTeamScore(Optional.ofNullable(count.getRedTeamScore()).orElse(0L))
        .setCreateTime(count.getCreateTime())).collect(Collectors.toList());
  }

  private Map<Long, RoomProfileDTO> getRoomMap(List<GameTeamPkCountDTO> gameTeamPkCounts) {
    return ResponseAssert.requiredSuccess(roomManagerClient.mapProfileByRoomIds(
        gameTeamPkCounts.stream().map(GameTeamPkCountDTO::getRoomId).filter(Objects::nonNull)
            .collect(Collectors.toSet())));
  }

  private Map<Long, UserProfileDTO> getProfileMap(List<GameTeamPkCountDTO> gameTeamPkCounts) {
    return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(
        gameTeamPkCounts.stream().map(GameTeamPkCountDTO::getMvpUserId).filter(Objects::nonNull)
            .collect(Collectors.toSet())));
  }
}
