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

import com.alibaba.fastjson.JSON;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.external.inner.endpoint.message.TrtcClient;
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.mq.business.model.event.task.TaskApprovalEvent;
import com.red.circle.mq.rocket.business.producer.TaskMqMessage;
import com.red.circle.other.app.convertor.live.RoomProfileAppConvertor;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.room.EntryRoomEntrantsCO;
import com.red.circle.other.app.dto.clientobject.room.EntryRoomProfileCO;
import com.red.circle.other.app.dto.clientobject.room.EntryRoomPropsCO;
import com.red.circle.other.app.dto.clientobject.room.EntryRoomResponseCO;
import com.red.circle.other.app.dto.clientobject.room.RoomThemeCO;
import com.red.circle.other.app.dto.cmd.room.RoomEntryCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService;
import com.red.circle.other.infra.database.cache.service.user.UserAgoraTokenCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
import com.red.circle.other.infra.database.mongo.entity.live.RoomSetting;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.live.RoomTouristService;
import com.red.circle.other.infra.database.mongo.service.live.RoomUserBlacklistService;
import com.red.circle.other.infra.database.rds.service.props.PropsRoomLockService;
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.material.PropsCommodityType;
import com.red.circle.other.inner.enums.material.PropsVipActualEquityEnum;
import com.red.circle.other.inner.enums.room.RoomEventEnum;
import com.red.circle.other.inner.enums.room.RoomTakeMicRoleEnum;
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.model.dto.user.WealthAndCharmLevelDTO;
import com.red.circle.other.inner.model.dto.user.props.UserPropsResourcesDTO;
import com.red.circle.other.inner.model.dto.user.props.UserUsePropsDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
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.sql.Timestamp;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

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

/**
 * 加入房间检测.
 *
 * @author pengliang on 2021/2/20
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoomEnterCmdExe {

  private final UserRegionGateway userRegionGateway;
  private final UserProfileGateway userProfileGateway;
  private final RoomTouristService roomTouristService;
  private final AdministratorService administratorService;
  private final PropsRoomLockService propsRoomLockService;
  private final UserProfileAppConvertor userProfileAppConvertor;
  private final RoomProfileAppConvertor roomProfileAppConvertor;
  private final RoomManagerCacheService roomManagerCacheService;
  private final RoomUserBlacklistService roomUserBlacklistService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final TrtcClient trtcClient;
  private final UserAgoraTokenCacheService userAgoraTokenCacheService;
  private final TaskMqMessage taskMqMessage;

  public EntryRoomResponseCO execute(RoomEntryCmd cmd) {
    //checkEntryUserId(cmd);

    //进入房间计数
    taskMqMessage.sendTask(TaskApprovalEvent.builder()
            .taskId(10)
            .userId(cmd.getReqUserId())
            .day(LocalDateTimeUtils.nowFormat("yyyy-MM-dd"))
            .build());

    RoomProfileManager manager = roomProfileManagerService.getById(cmd.getRoomId());

    entryRoomCheck(cmd, manager);

    setDefaultRoomSettingTakeMicRole(manager);

    UserProfileDTO ownUserProfile = userProfileAppConvertor.toUserProfileDTO(
        userProfileGateway.getByUserId(manager.getUserId())
    );

    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, ownUserProfile);
    //String token = createAgoraToken(cmd);
    String token = userAgoraTokenCacheService.getUserAgoraToken(cmd.getReqUserId(), cmd.getRoomId());
    if (Objects.isNull(token)) {
      token = trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody();
      log.warn("进房间token：{}", token);
      userAgoraTokenCacheService.save(token, cmd.getReqUserId(), cmd.getRoomId());
    }

    try {
      // 无法操作，错误归属
      ResponseAssert.isTrue(CommonErrorCode.INOPERABLE_WRONG_ATTRIBUTION,
              StringUtils.startsWith(
                      roomProfileManagerService.getRoomSysOrigin(cmd.getRoomId()),
                      cmd.requireReqSysOrigin()
              )
      );
      roomTouristService.add(cmd.requiredReqUserId(), cmd.getRoomId(), IdWorkerUtils.getId());
    } catch (Exception e) {
      log.error("进房间添加足迹异常：{}", e.getMessage());
    }

    return new EntryRoomResponseCO()
        .setRoomProfile(
            new EntryRoomProfileCO()
                .setUserProfile(ownUserProfile)
                .setRegionCode(userRegionGateway.getRegionCode(ownUserProfile.getId()))
                .setRoomProfile(toRoomProfileDTO(manager, ownUserProfile))
                .setRoomSetting(roomProfileAppConvertor.toRoomSettingCO(manager.getSetting()))
                .setRoomCounter(roomProfileAppConvertor.toRoomCounterDTO(manager.getCounter()))
        )
        .setRoomProps(
            new EntryRoomPropsCO()
                .setLayoutCode(getLayoutCode(ownUserProfile))
                .setRoomTheme(getRoomThemeCO(ownUserProfile))
        )
        .setEntrants(
            new EntryRoomEntrantsCO()
                .setRoles(roomManagerCacheService.getRoomUserRoles(cmd.getReqUserId(),
                    cmd.getRoomId()))
                .setLevel(getUserLevel(cmd.requireReqSysOriginEnum(), cmd.getReqUserId()))
                .setNobleVipAbility(listUserPropsVipActualEquity(cmd))
                    .setRoomToken(token)
        );
  }

  /**
   * 异步拿声网观众token，5分钟拿不到就返回默认一串字符串
   * @param cmd
   * @return
   */
  private String createAgoraToken(RoomEntryCmd cmd) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    AtomicReference<String> agoraToken = new AtomicReference<>("BaHrIypJdFWqwWtoZLToRucRyoGrVgYCONBFvGynmlJsevFYsWBfEIcaWUUGijQBjycTtmSvkmBINoSltJMmgiPeBnkaWErixaxg");
    Future<?> future = executor.submit(() -> {
      agoraToken.set(trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody());
    });

    try {
      future.get(3, TimeUnit.SECONDS); // 等待最多3秒
    } catch (TimeoutException e) {
      // 处理超时
      log.error("上麦获取声网token超时: {}", e.getMessage());
    } catch (InterruptedException | ExecutionException e) {
      // 处理其他异常
      log.error("上麦获取声网token其他异常: {}", e.getMessage());
    }

    executor.shutdown();
    return agoraToken.get();
  }

  private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(RoomEntryCmd cmd) {
    return userProfileGateway.listUserActualEquityEnum(cmd.requiredReqUserId());
  }

  private WealthAndCharmLevelDTO getUserLevel(SysOriginPlatformEnum sysOrigin, Long userId) {
    return Optional.ofNullable(
            userProfileGateway.getUserConsumptionLevel(sysOrigin, userId)
        ).map(level -> new WealthAndCharmLevelDTO()
            .setCharmLevel(Optional.ofNullable(level.getCharmLevel()).orElse(0))
            .setWealthLevel(Optional.ofNullable(level.getWealthLevel()).orElse(0)))
        .orElseGet(() -> new WealthAndCharmLevelDTO()
            .setCharmLevel(0)
            .setWealthLevel(0));
  }

  private void checkEntryUserId(RoomEntryCmd cmd) {
    if (cmd.checkAndroid() && cmd.buildVersion() >= 169) {
      ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getEntryUserId());
      if (!Objects.equals(cmd.getEntryUserId(), cmd.requiredReqUserId())) {
        log.warn("RoomEntry Error: {}", JacksonUtils.toJson(cmd));
        ResponseAssert.failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR, "Not match.");
      }
    }
  }

  private RoomThemeCO getRoomThemeCO(UserProfileDTO userProfile) {

    List<UserUsePropsDTO> usePropsEntities = userProfile.filterProps(
        useProps -> Objects.equals(useProps.getPropsResources().getType(),
            PropsCommodityType.THEME.name()));

    if (CollectionUtils.isEmpty(usePropsEntities)) {
      return null;
    }

    UserUsePropsDTO useProps = usePropsEntities.get(0);
    UserPropsResourcesDTO resources = useProps.getPropsResources();
    return new RoomThemeCO()
        .setId(resources.getId())
        .setThemeBack(resources.getCover())
        .setUseTheme(Boolean.TRUE)
        .setExpireTime(useProps.getExpireTime());
  }

  private String getLayoutCode(UserProfileDTO userProfile) {

    List<UserUsePropsDTO> usePropsEntities = userProfile.filterProps(
        useProps -> Objects.equals(useProps.getPropsResources().getType(),
            PropsCommodityType.LAYOUT.name()));

    if (CollectionUtils.isEmpty(usePropsEntities)) {
      return "";
    }

    UserUsePropsDTO useProps = usePropsEntities.get(0);
    return Optional.ofNullable(useProps.getPropsResources())
        .map(UserPropsResourcesDTO::getCode)
        .orElse(null);
  }

  /**
   * 进入房间前检查：密码/权限/黑名单/系统互通等.
   */
  private void entryRoomCheck(RoomEntryCmd cmd, RoomProfileManager manager) {
    // 房间不存在
    ResponseAssert.notNull(RoomErrorCode.ROOM_NOT_EXISTS, manager);
    ResponseAssert.isTrue(RoomErrorCode.ROOM_NOT_EXISTS,
        Objects.equals(manager.getDel(), Boolean.FALSE));

    // 检查平台系统来源
    checkSysOrigin(cmd.requiredReqUserId(), manager.getSysOrigin());

    boolean appAdmin = isAppAdmin(cmd);
    RoomSetting setting = manager.getSetting();
    List<RoomProfile> roomProfileList = roomProfileManagerService.listProfileByRoomIds(Set.of(cmd.getRoomId()));
    if (roomProfileList.size() > 0){
      Timestamp timestamp = propsRoomLockService.getExpireTime(roomProfileList.get(0).getUserId());
      if (Objects.nonNull(timestamp)){
        if (TimestampUtils.now().compareTo(timestamp) > 0){
          setting.setPassword(null);
          roomProfileManagerService.updatePassword(cmd.getRoomId(), "");
        }
      }else if (StringUtils.isNotBlank(setting.getPassword())){
        if (!Objects.isNull(timestamp)){
          setting.setPassword(null);
          roomProfileManagerService.updatePassword(cmd.getRoomId(), "");
        }


      }
    }
    manager.setSetting(setting);
    // 非管理员情况下， 验证房间是否已关闭
    if (!appAdmin) {
      ResponseAssert.isFalse(RoomErrorCode.ROOM_CLOSE,
          Objects.equals(manager.getEvent(), RoomEventEnum.CLOSE.name()));
    }

    if (cmd.reqIsSelf(manager.getUserId()) || appAdmin) {
      return;
    }

    // 用户在黑名单中
    ResponseAssert.isFalse(RoomErrorCode.USER_IS_BLACKLIST,
        roomUserBlacklistService.exists(cmd.getRoomId(), cmd.requiredReqUserId()));

    // 判断密码
    if (StringUtils.isNotBlank(setting.getPassword())) {
      // 密码不正确
      ResponseAssert.isTrue(RoomErrorCode.PASSWORD_NOT_TRUE,
          Objects.equals(setting.getPassword(), cmd.getPwd()));
    }

//    // 2023/12/7 刘占洋需求： 2fun不严重区域冲突
//    if (Objects.equals(cmd.requireReqSysOriginEnum(), SysOriginPlatformEnum.TWO_FUN)) {
//      return;
//    }
//
//    if (Objects.equals(cmd.requireReqSysOriginEnum(), SysOriginPlatformEnum.TARAB)) {
//      return;
//    }
    // 区域不互通
//    ResponseAssert.isTrue(RoomErrorCode.NO_RIGHT_TO_ENTER, userRegionGateway.checkBusinessRegion(cmd.getReqUserId(), manager.getUserId()));
  }

  /**
   * 校验进来的用户是否为App超级管理员.
   */
  private boolean isAppAdmin(RoomEntryCmd cmd) {
    return administratorService.existsSupperAdmin(cmd.requiredReqUserId());
  }

  private RoomProfileDTO toRoomProfileDTO(RoomProfileManager manager, UserProfileDTO userProfile) {
    RoomProfileDTO roomProfile = roomProfileAppConvertor.toRoomProfileDTO(manager);
    roomProfile.setCountryCode(userProfile.getCountryCode());
    roomProfile.setCountryName(userProfile.getCountryName());
    return roomProfile;
  }

  private void setDefaultRoomSettingTakeMicRole(RoomProfileManager manager) {
    if (Objects.isNull(manager) || Objects.isNull(manager.getSetting())) {
      return;
    }
    if (StringUtils.isBlank(manager.getSetting().getTakeMicRole())) {
      manager.getSetting().setTakeMicRole(RoomTakeMicRoleEnum.ALL.name());
    }
  }

  public void checkSysOrigin(Long userId, String sysOrigin) {
    SysOriginPlatformEnum reqUserOrigin = SysOriginPlatformEnum.valueOf(
        userProfileGateway.getSysOrigin(userId));

    ResponseAssert.notNull(RoomErrorCode.NO_RIGHT_TO_ENTER, reqUserOrigin);

    if (!SysOriginPlatformEnum.isVoiceSystem(reqUserOrigin)) {
      return;
    }

    // 无权进入
    ResponseAssert.isTrue(RoomErrorCode.NO_RIGHT_TO_ENTER, StringUtils.startsWith(Objects.toString(reqUserOrigin), sysOrigin));
  }


}
