package com.red.circle.other.app.command.game.teampk;

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.BroadcastGroupMsgBodyCmd;
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.GameIndoorTeamPkEvent;
import com.red.circle.mq.rocket.business.producer.GameMqMessage;
import com.red.circle.other.app.dto.clientobject.game.GameIndoorTeamPkBaseInfoCO;
import com.red.circle.other.app.dto.clientobject.game.GameIndoorTeamPkMsgCO;
import com.red.circle.other.app.dto.cmd.game.GameCreteIndoorPkCmd;
import com.red.circle.other.infra.database.cache.service.other.GameRoomPkCacheService;
import com.red.circle.other.infra.database.rds.entity.game.GameIndoorTeamPkRecord;
import com.red.circle.other.infra.database.rds.entity.game.GameRoomPkRecord;
import com.red.circle.other.infra.database.rds.service.game.GameIndoorTeamPkRecordService;
import com.red.circle.other.infra.database.rds.service.game.GameRoomPkRecordService;
import com.red.circle.other.infra.enums.game.GamePkBelongTeamEnum;
import com.red.circle.other.infra.enums.game.GameRoomPkTypeEnum;
import com.red.circle.other.inner.asserts.GameErrorCode;
import com.red.circle.tool.core.date.LocalDateTimeUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.time.temporal.ChronoUnit;
import java.util.Objects;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 房间内团队PK - 创建PK.
 *
 * @author pengshigang on 2022/03/03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GameCreateTeamPkCmdExe {

  private final ImGroupClient imGroupClient;
  private final GameMqMessage gameMqMessage;
  private final GameRoomPkCacheService gameRoomPkCacheService;
  private final GameRoomPkRecordService gameRoomPkRecordService;
  private final GameIndoorTeamPkRecordService gameIndoorTeamPkRecordService;

  public void execute(GameCreteIndoorPkCmd cmd) {

    ResponseAssert.isTrue(GameErrorCode.YOUR_GAME_NOT_OVER, isGameOver(cmd.getReqUserId()));
    ResponseAssert.isTrue(GameErrorCode.GAME_REPEAT, isCanGame(cmd));
    GameRoomPkRecord pkRecord = gameRoomPkRecordService.getEfficientPkByRoomId(cmd.getRoomId());
    if (Objects.nonNull(pkRecord)) {
      ResponseAssert.isTrue(GameErrorCode.GAME_REPEAT, Boolean.FALSE);
    }

    //组装pk记录
    GameIndoorTeamPkRecord saveData = buildPkRecord(cmd);
    gameIndoorTeamPkRecordService.save(saveData);
    cacheRoomPk(saveData);

    //发送通知
    sendMsg(cmd, saveData);

  }

  private GameIndoorTeamPkRecord buildPkRecord(GameCreteIndoorPkCmd cmd) {
    GameIndoorTeamPkRecord saveData = new GameIndoorTeamPkRecord()
        .setId(IdWorkerUtils.getId())
        .setRoomId(cmd.getRoomId())
        .setPkDuration(cmd.getPkDuration())
        .setSysOrigin(cmd.getReqSysOrigin().getOrigin())
        .setGameStatus(GameStateEnum.WAITING.name())
        .setBelongTeam(getBelongTeam(cmd));
    saveData.setCreateTime(TimestampUtils.now());
    saveData.setCreateUser(cmd.getReqUserId());
    return saveData;
  }

  private String getBelongTeam(GameCreteIndoorPkCmd cmd) {
    if (StringUtils.isBlank(cmd.getBelongTeam())) {
      return null;
    }
    return GamePkBelongTeamEnum.valueOf(cmd.getBelongTeam()).name();
  }

  private void cacheRoomPk(GameIndoorTeamPkRecord roomPk) {
    gameRoomPkCacheService.cacheIndoorTeamPkBaseInfo(roomPk.getId(),
        JacksonUtils.toJson(new GameIndoorTeamPkBaseInfoCO()
            .setSysOrigin(roomPk.getSysOrigin())
            .setId(roomPk.getId())
            .setUserId(roomPk.getCreateUser())
            .setRoomId(roomPk.getRoomId())
            .setBelongTeam(roomPk.getBelongTeam())
            .setGameStatus(roomPk.getGameStatus())
            .setEndTime(TimestampUtils.nowPlusMinutes(3))
        )
    );
  }

  private void sendMsg(GameCreteIndoorPkCmd cmd, GameIndoorTeamPkRecord pkRecord) {

    sendRedisMq(pkRecord.getId());

    imGroupClient.sendMessageBroadcast(BroadcastGroupMsgBodyCmd.builder()
        .type(GroupMessageTypeEnum.GAME_INDOOR_TEAM_PK)
        .data(new GameIndoorTeamPkMsgCO()
            .setId(pkRecord.getId())
            .setRoomId(cmd.getRoomId())
            .setUserId(cmd.getReqUserId())
            .setMsgType(GameRoomPkTypeEnum.GAME_ROOM_PK_SPONSOR.name())
            //发起的PK在未接收之前只有3分钟的生命周期
            .setOverTime(LocalDateTimeUtils
                .betweenTwoTime(TimestampUtils.now().toLocalDateTime(),
                    TimestampUtils.nowPlusMinutes(3).toLocalDateTime(),
                    ChronoUnit.SECONDS))
            .setRedTeamScore(0L)
            .setBlueTeamScore(0L)
        )
        .toPlatform(cmd.requireReqSysOriginEnum())
        .build());
  }

  private void sendRedisMq(Long pkId) {
    gameMqMessage.indoorTeamPkDelayed(new GameIndoorTeamPkEvent()
        .setGameId(pkId)
        .setState(GameStateEnum.WAITING)
        .setDelayMinutes(3L)
    );
  }

  private Boolean isCanGame(GameCreteIndoorPkCmd cmd) {

    return gameRoomPkRecordService.isCanGame(cmd.getReqUserId(), cmd.getRoomId()) &&
        gameIndoorTeamPkRecordService.isCanGame(cmd.getReqUserId(), cmd.getRoomId());
  }

  private Boolean isGameOver(Long userId) {
    return gameRoomPkRecordService.isCanJoinOrCreateGame(userId) &&
        gameIndoorTeamPkRecordService.checkCreateGame(userId);
  }


}
