package com.red.circle.other.app.command.room;

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.room.KickOffMicrophoneCmd;
import com.red.circle.other.domain.gateway.props.PropsNobleVipGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.entity.sys.ApiOperationLog;
import com.red.circle.other.infra.database.mongo.service.sys.ApiOperationLogService;
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
import com.red.circle.other.infra.database.rds.service.props.PropsVipActualEquityService;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.enums.live.RoomUserRolesEnum;
import com.red.circle.other.inner.enums.material.NobleVipEnum;
import com.red.circle.other.inner.enums.material.PropsCommodityType;
import com.red.circle.other.inner.model.dto.material.props.PropsNobleVipAbilityDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * T下麦克风.
 *
 * @author pengliang on 2021/9/10
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class KickOffMicrophoneCmdExe {

  private final RoomMemberService roomMemberService;
  private final UserProfileGateway userProfileGateway;
  private final AdministratorService administratorService;
  private final PropsNobleVipGateway propsNobleVipGateway;
  private final ApiOperationLogService apiOperationLogService;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final PropsVipActualEquityService propsVipActualEquityService;

  public boolean execute(KickOffMicrophoneCmd cmd) {
    apiOperationLogService.add(
        new ApiOperationLog()
            .setId(IdWorkerUtils.getIdStr())
            .setRequestUserId(cmd.requiredReqUserId())
            .setApiDesc("检查用户是否可以T麦克风")
            .setBusinessCode("APP_KICK_OFF_MICROPHONE")
            .setBusinessContent(Objects.toString(cmd.getRoomId()))
            .setCmd(JacksonUtils.toJson(cmd))
            .setExpiredTime(DateUtils.nowPlusDays(7))
            .setCreateTime(DateUtils.now())
    );

    if (cmd.checkAndroid() && cmd.buildVersion() >= 169) {

      ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getOpUserId());

      if (!Objects.equals(cmd.getOpUserId(), cmd.requiredReqUserId())) {
        log.warn("KickOffMicrophone Error: {}", JacksonUtils.toJson(cmd));
        ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR, "Not match.");
      }
    }

    // 不可操作自己
    ResponseAssert.isFalse(UserErrorCode.NOT_OPERATION_ME,
        Objects.equals(cmd.getKickUserId(), cmd.requiredReqUserId()));

    boolean kickUserIsSystemAdmin = administratorService.existsAdmin(cmd.getKickUserId());

    if (kickUserIsSystemAdmin) {
      log.warn("[KickOffMicrophone] Not kick super administrator {}", JacksonUtils.toJson(cmd));
      return Boolean.FALSE;
    }

    boolean reqUserIsSystemAdmin = administratorService.existsAdmin(cmd.requiredReqUserId());

    // 允许踢除超级管理员外的任何人
    if (reqUserIsSystemAdmin) {
      //发送踢人广播
      sendKickMsg(cmd, String
          .format("[KickOffMicrophone]%s: %s 踢 %s",
              cmd.requireReqSysOriginEnum(),
              cmd.requiredReqUserId(),
              cmd.getKickUserId()));
      return Boolean.TRUE;
    }

    // 是否无法将VIP5用户移出房间: true 无法移出
    if (Boolean.TRUE.equals(notKickOutRoom(cmd.getKickUserId()))) {
      log.info("[KickOffMicrophone] Can't kick VIP 5 out of the room");
      ResponseAssert.failure(CommonErrorCode.INSUFFICIENT_PERMISSION,"Insufficient permission");
    }

    Map<Long, RoomUserRolesEnum> rolesMapping = roomMemberService
        .mapMemberRoles(cmd.getRoomId(),
            Set.of(cmd.getKickUserId(), cmd.requiredReqUserId()));

    if (CollectionUtils.isEmpty(rolesMapping)) {
      log.warn("[KickOffMicrophone] Query roles error {},{}", rolesMapping,
          JacksonUtils.toJson(cmd));
      return Boolean.FALSE;
    }

    RoomUserRolesEnum operationUserRoles = rolesMapping.get(cmd.requiredReqUserId());
    RoomUserRolesEnum kickUserRoles = rolesMapping.get(cmd.getKickUserId());

    if (!isHavePermission(operationUserRoles)) {
      log.warn("[KickOffMicrophone] OperationUserRoles not have permission {},[{} -> {}]",
          JacksonUtils.toJson(cmd),
          operationUserRoles, kickUserRoles);
      return Boolean.FALSE;
    }

    if (Objects.equals(RoomUserRolesEnum.HOMEOWNER, kickUserRoles)) {
      log.warn("[KickOffMicrophone] KickUserRoles is Homeowner {},[{} -> {}]",
          JacksonUtils.toJson(cmd),
          operationUserRoles, kickUserRoles);
      return Boolean.FALSE;
    }

    if (Objects.equals(operationUserRoles, kickUserRoles)) {
      log.warn("[KickOffMicrophone] Not have permission;Equal rights {},[{} -> {}]",
          JacksonUtils.toJson(cmd),
          operationUserRoles, kickUserRoles);
      return Boolean.FALSE;
    }

    //发送踢人广播
    sendKickMsg(cmd, String
        .format("[KickOffMicrophone]%s: %s(%s) 踢 %s(%s)",
            cmd.requireReqSysOrigin(),
            cmd.requiredReqUserId(),
            operationUserRoles, cmd.getKickUserId(), kickUserRoles));

    return Boolean.TRUE;
  }

  private void sendKickMsg(KickOffMicrophoneCmd cmd, String msg) {
    apiOperationLogService.add(
        new ApiOperationLog()
            .setId(IdWorkerUtils.getIdStr())
            .setRequestUserId(cmd.requiredReqUserId())
            .setApiDesc("T下麦克风: " + msg)
            .setBusinessCode("KICK_OFF_MICROPHONE_PHONE")
            .setBusinessContent(Objects.toString(cmd.getRoomId()))
            .setCmd(JacksonUtils.toJson(cmd))
            .setExpiredTime(DateUtils.nowPlusDays(7))
            .setCreateTime(DateUtils.now())
    );
  }

  private boolean isHavePermission(RoomUserRolesEnum roles) {
    return Objects.equals(RoomUserRolesEnum.ADMIN, roles)
        || Objects.equals(RoomUserRolesEnum.HOMEOWNER, roles);
  }


  /**
   * 不能被剔除房间
   *
   * @return true:无法移除 false:允许移除
   */
  private Boolean notKickOutRoom(Long userId) {

    UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(userId));
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);
    Long wearNobleVipSourceId = getWearNobleVipSourceId(userProfile);

    if (Objects.isNull(wearNobleVipSourceId)) {
      return Boolean.FALSE;
    }

    if (!propsVipActualEquityService.existsNotExpiredPropsId(wearNobleVipSourceId)) {
      return Boolean.FALSE;
    }

    PropsNobleVipAbilityDTO vipAbilities = propsNobleVipGateway.getAbilityDTO(
        wearNobleVipSourceId);
    if (Objects.isNull(vipAbilities)) {
      return Boolean.FALSE;
    }

    return Objects.equals(vipAbilities.getVipType(), NobleVipEnum.KING.name()) ||
        Objects.equals(vipAbilities.getVipType(), NobleVipEnum.EMPEROR.name());
  }

  private Long getWearNobleVipSourceId(UserProfileDTO userProfile) {
    return userProfile.filterProps(
            props -> Objects.nonNull(props.getPropsResources()) && PropsCommodityType.NOBLE_VIP.eq(
                props.getPropsResources().getType())).stream().findFirst()
        .map(props -> props.getPropsResources().getId())
        .orElse(null);
  }

}
