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

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.endpoint.message.TrtcClient;
import com.red.circle.external.inner.model.cmd.message.GroupBanCmd;
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
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.live.inner.endpoint.LiveMicClient;
import com.red.circle.other.app.dto.clientobject.room.RoomBlackProcessCO;
import com.red.circle.other.app.dto.cmd.room.RoomBlackCmd;
import com.red.circle.other.domain.gateway.props.PropsNobleVipGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.entity.live.RoomUserBlacklist;
import com.red.circle.other.infra.database.mongo.entity.sys.ApiOperationLog;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.live.RoomUserBlacklistService;
import com.red.circle.other.infra.database.mongo.service.sys.ApiOperationLogService;
import com.red.circle.other.infra.database.rds.entity.live.RoomMember;
import com.red.circle.other.infra.database.rds.service.live.RoomMemberService;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorAuthService;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.inner.asserts.RoomErrorCode;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
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.enums.material.PropsVipActualEquityEnum;
import com.red.circle.other.inner.model.dto.material.props.PropsNobleVipAbilityDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateUtils;
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.util.Collections;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 加入房间黑名单.
 *
 * @author houyong on 2020/12/3
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoomBlackJoinCmdExe {

  private final TrtcClient trtcClient;
  private final ImGroupClient imGroupClient;
  private final RoomMemberService roomMemberService;
  private final UserProfileGateway userProfileGateway;
  private final AdministratorService administratorService;
  private final PropsNobleVipGateway propsNobleVipGateway;
  private final ApiOperationLogService apiOperationLogService;
  private final EnumConfigCacheService enumConfigCacheService;
  private final RoomUserBlacklistService roomUserBlacklistService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final LiveMicClient liveMicClient;
  private final AdministratorAuthService administratorAuthService;

  public RoomBlackProcessCO execute(RoomBlackCmd cmd) {

    apiOperationLogService.add(
        new ApiOperationLog()
            .setId(IdWorkerUtils.getIdStr())
            .setRequestUserId(cmd.requiredReqUserId())
            .setApiDesc("加入黑名单")
            .setBusinessCode("JOIN_BLACKLIST")
            .setBusinessContent(Objects.toString(cmd.getRoomId()))
            .setCmd(JacksonUtils.toJson(cmd))
            .setExpiredTime(DateUtils.nowPlusDays(7))
            .setCreateTime(DateUtils.now())
    );

    if (cmd.getOutTime() <= 0) {
      log.warn("RoomBlackProcessCO 请求时间参数错误:{}", cmd.getOutTime());
      ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR);
      return null;
    }

    List<String> authResources = administratorAuthService.listAuthResources(cmd.getUserId());
    ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION, authResources.contains("KICK_ROOM"));

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

    String superAdminIds = enumConfigCacheService.getValue(EnumConfigKey.ASWAT_ADMINS,
        cmd.requireReqSysOrigin());
    // 权限不足: 不可操作管理员
    ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
        StringUtils.isNotBlank(superAdminIds) && superAdminIds
            .contains(String.valueOf(cmd.getUserId())));

    UserProfile beBlackUserProfile = userProfileGateway.getByUserId(cmd.getUserId());
    // 没有找到用户信息
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, beBlackUserProfile);

    // 房间不存在
    RoomProfile beBlackRoomProfile = roomProfileManagerService.getProfileById(cmd.getRoomId());
    ResponseAssert.notNull(RoomErrorCode.ROOM_NOT_EXISTS, beBlackRoomProfile);

    RoomMember requestMember = roomMemberService
        .getRoomMember(cmd.getRoomId(), cmd.requiredReqUserId());
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, requestMember);

    if (!(StringUtils.isNotBlank(superAdminIds) && superAdminIds
        .contains(String.valueOf(cmd.requiredReqUserId())))) {

      Long wearNobleVipSourceId = getWearNobleVipSourceId(beBlackUserProfile);
      PropsNobleVipAbilityDTO vipAbilities = propsNobleVipGateway.getAbilityDTO(
          wearNobleVipSourceId);

      Boolean vip = Objects.nonNull(vipAbilities) && (Objects.equals(vipAbilities.getVipType(),
          NobleVipEnum.EMPEROR.name())||Objects.equals(vipAbilities.getVipType(),
          NobleVipEnum.KING.name()));

      // 2043 权限不足
      ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION, vip);

      // 2023-9-7仅房主可以踢VIP，vip5、6不能踢
      if (!requestMember.checkHomeowner()) {
        // 实际VIP权益
        List<PropsVipActualEquityEnum> vipActualList = listUserPropsVipActualEquity(
            beBlackUserProfile);
        // 2043 权限不足
        ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
            CollectionUtils.isNotEmpty(vipActualList) && vipActualList
                .contains(PropsVipActualEquityEnum.PROHIBIT_KICK));
      }
    }

    // 超级管理员除了不能拉黑本房间房主，其余都可以拉黑
    if (StringUtils.isNotBlank(superAdminIds) && superAdminIds
        .contains(String.valueOf(cmd.requiredReqUserId()))) {
      superAdminBlacklist(cmd, beBlackUserProfile, beBlackRoomProfile);
      return new RoomBlackProcessCO()
          .setRoomId(cmd.getRoomId())
          .setRoles("SUPER_ADMIN")
          .setRemark("系统管理员");
    }

    // 权限不足(必须是房主/管理员)
//    ResponseAssert.isTrue(CommonErrorCode.INSUFFICIENT_PERMISSION,
//        requestMember.checkHomeownerOrAdmin());

    RoomMember beOptMember = roomMemberService
        .getRoomMember(cmd.getRoomId(), cmd.getUserId());

    // 如果为空表示被操作人角色为游客
    if (Objects.nonNull(beOptMember)) {
      // 不能是房主
      ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
          beOptMember.checkHomeowner());

      // 权限不能相同
      ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
          Objects.equals(beOptMember.getRoles(), requestMember.getRoles()));
    }

    // 权限不足
    ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
        Objects.equals(beBlackRoomProfile.getUserId(), cmd.getUserId()));

    List<Long> roomOnlineUserIds = ResponseAssert.requiredSuccess(liveMicClient.getLiveRoomUserIds(cmd.getRoomId(), 200));
    if (CollectionUtils.isEmpty(roomOnlineUserIds) || !roomOnlineUserIds.contains(beBlackUserProfile.getId())) {
      log.info("用户不在房间，无法拉黑 createUserId:{} roomOnlineUserIds:{} blackUserId:{}", cmd.requiredReqUserId(), roomOnlineUserIds, beBlackUserProfile.getId());
      return null;
    }

    Boolean isSuccess = ResponseAssert.requiredSuccess(
        imGroupClient.banGroupMember(new GroupBanCmd()
            .setGroupId(beBlackRoomProfile.getRoomAccount())
            .setUserId(beBlackUserProfile.getId())
            .setDuration(cmd.getOutTime() * 60)
            .setDescription(cmd.requiredReqUserId()
                + "#"
                + requestMember.getRoles()
                + "#"
                + beBlackUserProfile.getId())
        )
    );

    log.info("imGroupClient拉黑结果:{}", isSuccess);
//    if (Objects.equals(isSuccess, Boolean.TRUE)) {
    roomUserBlacklistService.add(new RoomUserBlacklist()
            .setTimingId(IdWorker.getId())
            .setSysOrigin(cmd.requireReqSysOrigin())
            .setUserId(beBlackUserProfile.getId())
            .setRoomId(beBlackRoomProfile.getId())
            .setCreateUserRoles(requestMember.getRoles())
            .setCreateUser(cmd.requiredReqUserId())
            .setExpiredTime(TimestampUtils.nowPlusMinutes(cmd.getOutTime()))
            .setCreateTime(TimestampUtils.now())
    );
//    }

    trtcClient.removeUser(new TrtcRemoveUserCmd()
        .setRoomId(Long.parseLong(beBlackRoomProfile.getRoomAccount()))
        .setUserIds(Collections.singletonList(beBlackUserProfile.getId()))
        .setLogOrigin("黑名单"));

    return new RoomBlackProcessCO()
        .setRoomId(cmd.getRoomId())
        .setRoles(requestMember.getRoles())
        .setRemark("常规操作");
  }

  private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(UserProfile userProfile) {
    return userProfileGateway.listUserActualEquityEnum(userProfile.getId());
  }

  private void superAdminBlacklist(RoomBlackCmd cmd, UserProfile baseInfo,
      RoomProfile roomProfile) {

    RoomMember beOptMember = roomMemberService.getRoomMember(cmd.getRoomId(), cmd.getUserId());

    ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
        Objects.nonNull(beOptMember) && beOptMember.checkHomeowner());

    RoomMember requestMember = roomMemberService
        .getRoomMember(cmd.getRoomId(), cmd.requiredReqUserId());

    roomUserBlacklistService.add(new RoomUserBlacklist()
        .setTimingId(IdWorker.getId())
        .setSysOrigin(cmd.requireReqSysOrigin())
        .setUserId(baseInfo.getId())
        .setRoomId(roomProfile.getId())
        .setCreateUserRoles(Objects.isNull(requestMember) ? RoomUserRolesEnum.ADMIN.name()
            : requestMember.getRoles())
        .setCreateUser(cmd.requiredReqUserId())
        .setExpiredTime(TimestampUtils.nowPlusMinutes(cmd.getOutTime()))
    );
  }

  private Long getWearNobleVipSourceId(UserProfile 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);
  }

}
