package com.red.circle.other.app.manager.game;

import com.red.circle.common.business.core.enums.CommonErrorEnum;
import com.red.circle.common.business.core.enums.GameStateEnum;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.model.cmd.message.CustomGroupMsgBodyCmd;
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.mq.business.model.event.game.GameRoomPkEvent;
import com.red.circle.other.app.dto.clientobject.game.GameRoomPkMsgCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.entity.game.pk.GameRoomPkCount;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.service.game.GamePkCountService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.game.GameRoomPkIntegralRecord;
import com.red.circle.other.infra.database.rds.entity.game.GameRoomPkRecord;
import com.red.circle.other.infra.database.rds.entity.game.GameRoomPkWinnerRecord;
import com.red.circle.other.infra.database.rds.service.game.GameRoomPkIntegralRecordService;
import com.red.circle.other.infra.database.rds.service.game.GameRoomPkRecordService;
import com.red.circle.other.infra.database.rds.service.game.GameRoomPkWinnerRecordService;
import com.red.circle.other.infra.enums.game.GameRoomPkTypeEnum;
import com.red.circle.other.inner.enums.game.GamePkTypeEnum;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.util.List;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 处理房间PK业务.
 *
 * @author pengshigang
 * @since 2021-9-27
 */
@Slf4j
@Component
@AllArgsConstructor
public class GameRoomPkManager {

  private final GamePkCountService gamePkCountService;
  private final ImGroupClient imGroupManagerService;
  private final GameRoomPkRecordService gameRoomPkRecordService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final GameRoomPkWinnerRecordService gameRoomPkWinnerRecordService;
  private final UserProfileGateway userProfileGateway;
  private final GameRoomPkIntegralRecordService gameRoomPkIntegralRecordService;

  public void processRoomPk(GameRoomPkEvent event) {
    Long pkId = event.getGameId();
    GameRoomPkRecord pkRecord = gameRoomPkRecordService.getById(pkId);
    if (isEnd(pkRecord, event.getState())) {
      return;
    }
    if (Objects.equals(pkRecord.getGameStatus(), GameStateEnum.WAITING.name())) {
      updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_EXPIRED_OVER, 0L, "");
      return;
    }

    List<GameRoomPkIntegralRecord> pkIntegralRecords = getTotalIntegralAndUserIdByPkId(pkId);
    if (CollectionUtils.isEmpty(pkIntegralRecords)) {
      updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_NO_WINNER_OVER, 0L, "");
      return;
    }

    addCount(pkId, pkRecord, pkIntegralRecords);

    gameRoomPkIntegralRecordService.saveIntegralToFansByPkId(pkId);

    gameRoomPkWinnerRecordService.save(getGameRoomPkWinnerRecord(pkRecord,
        processWinnerBusinessResultWinnerUserOrRoomId(pkRecord, pkIntegralRecords),
        pkIntegralRecords));

  }

  private void addCount(Long pkId, GameRoomPkRecord pkRecord,
      List<GameRoomPkIntegralRecord> pkIntegralRecords) {

    GameRoomPkCount pkRecordCount =new  GameRoomPkCount()
        .setId(pkId)
        .setSysOrigin(pkRecord.getSysOrigin())
        .setPkType(pkRecord.getPkType())
        .setCreateTime(pkRecord.getCreateTime())
        .setExpiredTime(TimestampUtils.nowPlusDays(30))
        .setRecipientRoomId(pkRecord.getRecipientRoomId())
        .setRecipientUserId(pkRecord.getRecipientUserId())
        .setSponsorUserId(pkRecord.getSponsorUserId())
        .setSponsorRoomId(pkRecord.getSponsorRoomId());
    processingPointsCount(pkIntegralRecords, pkRecordCount);
    gamePkCountService.addRoomPk(pkRecordCount);
  }

  private void processingPointsCount(List<GameRoomPkIntegralRecord> pkIntegralRecords,
      GameRoomPkCount pkRecordCount) {

    pkIntegralRecords.forEach(pkIntegral -> {

      if (Objects.equals(pkRecordCount.getPkType(), GamePkTypeEnum.ROOM_VS_ROOM.name())) {
        if (Objects.equals(pkIntegral.getReceiverUserId(), pkRecordCount.getRecipientRoomId())) {
          pkRecordCount.setRecipientIntegral(pkIntegral.getIntegral());
        }
        if (Objects.equals(pkIntegral.getReceiverUserId(), pkRecordCount.getSponsorRoomId())) {
          pkRecordCount.setSponsorIntegral(pkIntegral.getIntegral());
        }
        return;
      }
      if (Objects.equals(pkIntegral.getReceiverUserId(), pkRecordCount.getRecipientUserId())) {
        pkRecordCount.setRecipientIntegral(pkIntegral.getIntegral());
      }
      if (Objects.equals(pkIntegral.getReceiverUserId(), pkRecordCount.getSponsorUserId())) {
        pkRecordCount.setSponsorIntegral(pkIntegral.getIntegral());
      }

    });
  }

  /**
   * 保存优胜者信息
   */
  private GameRoomPkWinnerRecord getGameRoomPkWinnerRecord(GameRoomPkRecord gameRoomPkRecord,
      Long winnerId, List<GameRoomPkIntegralRecord> pkIntegralRecords) {

    return new  GameRoomPkWinnerRecord()
        .setId(IdWorkerUtils.getId())
        .setUserId(winnerId)
        .setType(Boolean.FALSE)
        .setSysOrigin(gameRoomPkRecord.getSysOrigin())
        .setPkType(gameRoomPkRecord.getPkType())
        .setIntegral(pkIntegralRecords.get(0).getIntegral())
        .setTotalIntegral(getTotalIntegral(pkIntegralRecords));
  }

  /**
   * 处理优胜者业务并返回优胜者的用户id或房间ID
   */
  private Long processWinnerBusinessResultWinnerUserOrRoomId(GameRoomPkRecord pkRecord,
      List<GameRoomPkIntegralRecord> pkIntegralRecords) {

    Long aIntegral = pkIntegralRecords.get(0).getIntegral();
    Long aUserId = pkIntegralRecords.get(0).getReceiverUserId();

    log.warn("aIntegral：{},{}", aIntegral, aUserId);
    log.warn("pkIntegralRecords：{}", pkIntegralRecords);
    if(pkIntegralRecords.size() >= 2) {
      Long aIntegral1 = pkIntegralRecords.get(1).getIntegral();
      if (aIntegral1.equals(aIntegral)) {
        // 处理平局情况
        log.warn("房间pk对局平局 {},{},{}", pkRecord, aIntegral, aIntegral1);
        updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_NO_WINNER_OVER, 0L, "");
        return 0L;
      }
    }
    if (pkIntegralRecords.size() == 1) {
      log.warn("pkIntegralRecords.size()：{}", pkIntegralRecords.size());
      updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_RESULT, aIntegral,
          getAvatar(pkRecord.getPkType(), aUserId));
      return aUserId;
    }

    if (isEqualPoints(pkIntegralRecords)) {
      log.warn("pkIntegralRecords222222：{}", pkIntegralRecords);
      updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_RESULT, aIntegral,
          getAvatar(pkRecord.getPkType(), pkRecord.getSponsorUserId()));
      return pkRecord.getSponsorUserId();
    }

    log.warn("pkRecord：{}", pkRecord);
    updateGameState(pkRecord, GameRoomPkTypeEnum.GAME_ROOM_PK_RESULT, aIntegral,
        getAvatar(pkRecord.getPkType(), aUserId));
    return aUserId;
  }


  /**
   * 修改状态为【时间过期结束】，并删除redis pk数据.
   */
  private void updateGameState(GameRoomPkRecord pkRecord,
      GameRoomPkTypeEnum roomPkType, Long totalPoints, String avatar) {

    pkRecord.setGameStatus(getGameState(pkRecord));
    pkRecord.setUpdateTime(TimestampUtils.now());
    gameRoomPkRecordService.updateSelectiveById(pkRecord);
    sendMsg(pkRecord.getSponsorRoomId(), roomPkType, totalPoints, avatar);
  }


  /**
   * 发送消息
   *
   * @param roomId             房间ID
   * @param gameRoomPkTypeEnum 结束类型
   */
  private void sendMsg(Long roomId, GameRoomPkTypeEnum gameRoomPkTypeEnum,
      Long totalPoints, String avatar) {
    RoomProfile roomProfile = roomProfileManagerService.getProfileById(roomId);
    GameRoomPkMsgCO gameRoomPkMsgCO = new GameRoomPkMsgCO()
            .setSponsorRoomId(roomId)
            .setWinnerCover(avatar)
            .setWinnerIntegral(totalPoints)
            .setMsgType(gameRoomPkTypeEnum.name());
    log.warn("下发PK消息:{}, {}" , gameRoomPkTypeEnum.name(), gameRoomPkMsgCO);
    imGroupManagerService.sendCustomMessage(
        roomProfile.getRoomAccount(),
        CustomGroupMsgBodyCmd.builder()
            .type(GroupMessageTypeEnum.GAME_ROOM_PK)
            .data(
                new GameRoomPkMsgCO()
                    .setSponsorRoomId(roomId)
                    .setWinnerCover(avatar)
                    .setWinnerIntegral(totalPoints)
                    .setMsgType(gameRoomPkTypeEnum.name()))
            .build());

  }

  /**
   * 该局游戏是否已结束.
   */
  private boolean isEnd(GameRoomPkRecord gameRoomPkRecord, GameStateEnum msgStateEnum) {

    if (Objects.isNull(gameRoomPkRecord)) {
      return true;
    }

    if (Objects.equals(GameStateEnum.STARTED.name(), gameRoomPkRecord.getGameStatus()) &&
        Objects.equals(msgStateEnum, GameStateEnum.WAITING)) {
      //数据库状态为 pk中，但订阅消息传过来的是 等待中 则不处理任何业务
      return true;
    }

    return Objects.equals(gameRoomPkRecord.getGameStatus(), GameStateEnum.END.name()) ||
        Objects.equals(gameRoomPkRecord.getGameStatus(), GameStateEnum.EXPIRED_END.name()) ||
        Objects.equals(gameRoomPkRecord.getGameStatus(), GameStateEnum.VOLUNTARILY_END.name());
  }

  /**
   * 获得总积分 + 满足条件的额外分值
   */
  private Long getTotalIntegral(List<GameRoomPkIntegralRecord> pkIntegralRecords) {

    Long integral = 0L;

    for (GameRoomPkIntegralRecord record : pkIntegralRecords) {
      integral += record.getIntegral();
    }

    if (integral < 4000) {
      return integral;
    }

    if (integral <= 18999) {
      return integral + new Double(integral * 0.02).longValue();
    }

    if (integral <= 79999) {
      return integral + new Double(integral * 0.05).longValue();
    }

    return integral + new Double(integral * 0.1).longValue();

  }


  private boolean isEqualPoints(List<GameRoomPkIntegralRecord> pkIntegralRecords) {
    return Objects.equals(pkIntegralRecords.get(0).getIntegral(),
        pkIntegralRecords.get(1).getIntegral());
  }

  private String getGameState(GameRoomPkRecord gameRoomPkRecord) {
    return Objects.equals(GameStateEnum.WAITING.name(), gameRoomPkRecord.getGameStatus()) ?
        GameStateEnum.EXPIRED_END.name() : GameStateEnum.END.name();

  }

  private List<GameRoomPkIntegralRecord> getTotalIntegralAndUserIdByPkId(Long pkId) {
    return gameRoomPkIntegralRecordService.getTotalIntegralAndUserIdByPkId(pkId);
  }

  private String getAvatar(String pkType, Long id) {
    if (Objects.equals(GamePkTypeEnum.ROOM_VS_ROOM.name(), pkType)) {
      RoomProfile roomProfile = roomProfileManagerService.getProfileById(id);
      ResponseAssert.notNull(CommonErrorEnum.ROOM_NOT_EXIST, roomProfile);
      return roomProfile.getRoomCover();
    }
    return userProfileGateway.getByUserId(id).getUserAvatar();
  }


}
