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

import com.red.circle.common.business.core.enums.GameStateEnum;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd;
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.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.service.game.GameIndoorTeamPkRecordService;
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 java.sql.Timestamp;
import java.time.temporal.ChronoUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 游戏相关.
 *
 * @author lisizhe on 2023/9/21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GameStartTeamPkCmdExe {

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

  public void execute(AppIdLongCmd cmd) {

    ResponseAssert.isTrue(GameErrorCode.NO_GAME_RECORD_FOUND, isRole(cmd));
    GameIndoorTeamPkRecord pkRecord = gameIndoorTeamPkRecordService.getById(cmd.getId());
    pkRecord.setGameStatus(GameStateEnum.STARTED.name());
    pkRecord.setEndTime(getEndTime(pkRecord));
    pkRecord.setUpdateTime(TimestampUtils.now());
    pkRecord.setUpdateUser(cmd.getReqUserId());
    gameIndoorTeamPkRecordService.updateSelectiveById(pkRecord);
    pkRecord.setSysOrigin(cmd.getReqSysOrigin().getOrigin());
    cacheRoomPk(pkRecord);

    sendRedisMq(pkRecord);

    sendMsg(pkRecord);

  }

  private void sendRedisMq(GameIndoorTeamPkRecord pkRecord) {
    gameMqMessage.indoorTeamPkDelayed(new GameIndoorTeamPkEvent()
        .setGameId(pkRecord.getId())
        .setState(GameStateEnum.STARTED)
        .setDelayMinutes(pkRecord.getPkDuration())
    );
  }

  private void cacheRoomPk(GameIndoorTeamPkRecord game) {

    GameIndoorTeamPkBaseInfoCO pk = gameRoomPkCacheService
        .getIndoorTeamPkBaseInfo(game.getId(), GameIndoorTeamPkBaseInfoCO.class);

    ResponseAssert.notNull(GameErrorCode.GAME_OVER, pk);

    pk.setGameStatus(game.getGameStatus());
    pk.setEndTime(game.getEndTime());
    gameRoomPkCacheService.cacheIndoorTeamPkBaseInfo(game.getId(), JacksonUtils.toJson(pk));
  }

  private Timestamp getEndTime(GameIndoorTeamPkRecord pkRecord) {
    return TimestampUtils.nowPlusMinutes(pkRecord.getPkDuration());
  }

  private Boolean isRole(AppIdLongCmd cmd) {
    return gameIndoorTeamPkRecordService.checkStartGame(cmd.getReqUserId(), cmd.getId());
  }

  private void sendMsg(GameIndoorTeamPkRecord game) {

    imGroupClient
        .sendMessageBroadcast(
            BroadcastGroupMsgBodyCmd.builder().type(GroupMessageTypeEnum.GAME_INDOOR_TEAM_PK)
                .data(new GameIndoorTeamPkMsgCO()
                    .setId(game.getId())
                    .setRoomId(game.getRoomId())
                    .setUserId(game.getCreateUser())
                    .setMsgType(GameRoomPkTypeEnum.GAME_ROOM_PK_ACCEPT.name())
                    .setOverTime(LocalDateTimeUtils
                        .betweenTwoTime(TimestampUtils.now().toLocalDateTime(),
                            game.getEndTime().toLocalDateTime(), ChronoUnit.SECONDS))
                    .setRedTeamScore(0L)
                    .setBlueTeamScore(0L)
                ).toPlatform(SysOriginPlatformEnum.valueOf(game.getSysOrigin()))
                .build());

  }

}
