package com.red.circle.console.app.service.app.room;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.console.app.convertor.room.RoomProfileManagerAppConvertor;
import com.red.circle.console.app.dto.clienobject.room.OnlineRoomCO;
import com.red.circle.console.app.dto.clienobject.room.RoomApprovalCO;
import com.red.circle.console.app.dto.clienobject.room.RoomProfileManagerCO;
import com.red.circle.console.app.dto.clienobject.room.RoomTouristCO;
import com.red.circle.console.app.dto.clienobject.room.RoomUserBlacklistCO;
import com.red.circle.console.app.dto.cmd.app.room.ApprovalConsolePageQryCmd;
import com.red.circle.console.app.dto.cmd.app.room.RoomRemoveOrPullBlackUserCmd;
import com.red.circle.console.app.dto.cmd.app.room.RoomTouristQryCmd;
import com.red.circle.console.app.dto.enums.RoomRemoveUserEventEnum;
import com.red.circle.console.app.service.app.sys.SysBadgeConfigService;
import com.red.circle.console.app.service.app.sys.SysCountryCodeService;
import com.red.circle.console.inner.error.ConsoleErrorCode;
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
import com.red.circle.external.inner.endpoint.message.NewsletterClient;
import com.red.circle.external.inner.endpoint.message.TrtcClient;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.external.inner.model.cmd.message.GroupUnbanCmd;
import com.red.circle.external.inner.model.cmd.message.NewsletterResultCmd;
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
import com.red.circle.external.inner.model.enums.message.NewsletterEvent;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.inner.asserts.RoomErrorCode;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.endpoint.approval.ApprovalUserSettingDataClient;
import com.red.circle.other.inner.endpoint.live.ActiveVoiceRoomClient;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.endpoint.live.RoomTouristClient;
import com.red.circle.other.inner.endpoint.live.RoomUserBlacklistClient;
import com.red.circle.other.inner.endpoint.material.props.RoomBadgeClient;
import com.red.circle.other.inner.endpoint.user.user.UserOnlineClient;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.enums.room.RoomEventEnum;
import com.red.circle.other.inner.enums.user.UserOnlineStatusEnum;
import com.red.circle.other.inner.model.cmd.live.AppActiveVoiceRoomQryCmd;
import com.red.circle.other.inner.model.cmd.live.RoomBlacklistQryCmd;
import com.red.circle.other.inner.model.cmd.room.RoomProfileOpsQryCmd;
import com.red.circle.other.inner.model.cmd.tools.UserRoomRegionUpdateCmd;
import com.red.circle.other.inner.model.dto.approval.ApprovalUserSettingDataDTO;
import com.red.circle.other.inner.model.dto.live.ActiveVoiceRoomDTO;
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
import com.red.circle.other.inner.model.dto.live.RoomProfileManagerDTO;
import com.red.circle.other.inner.model.dto.live.RoomTouristDTO;
import com.red.circle.other.inner.model.dto.live.RoomUserBlacklistDTO;
import com.red.circle.other.inner.model.dto.live.UseRoomBadgeDTO;
import com.red.circle.other.inner.model.dto.material.BadgePictureConfigDTO;
import com.red.circle.other.inner.model.dto.material.RoomBadgeBackpackDTO;
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
import com.red.circle.other.inner.model.dto.user.OnlineUserDTO;
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.TimestampUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 房间资料管理.
 *
 * @author pengliang on 2023/11/17
 */
@Service
@RequiredArgsConstructor
public class RoomProfileManagerServiceImpl implements RoomProfileManagerService {

  private final TrtcClient trtcClient;
  private final ImGroupClient imGroupClient;
  private final RoomBadgeClient roomBadgeClient;
  private final NewsletterClient newsletterClient;
  private final UserOnlineClient userOnlineClient;
  private final UserProfileClient userProfileClient;
  private final RoomManagerClient roomManagerClient;
  private final RoomTouristClient roomTouristClient;
  private final SysBadgeConfigService sysBadgeConfigService;
  private final ActiveVoiceRoomClient activeVoiceRoomClient;
  private final RoomUserBlacklistClient roomUserBlacklistClient;
  private final SysCountryCodeService countryCodeService;
  private final ApprovalUserSettingDataClient approvalUserSettingDataClient;
  private final RoomProfileManagerAppConvertor roomProfileManagerAppConvertor;

  @Override
  public List<RoomProfileManagerDTO> listOps(RoomProfileOpsQryCmd qryCmd) {
    return roomManagerClient.listOps(qryCmd).getBody();
  }

  @Override
  public RoomProfileDTO getProfileById(Long roomId) {
    return roomManagerClient.getProfileById(roomId).getBody();
  }

  @Override
  public RoomProfileManagerCO getDetails(Long roomId) {
    RoomProfileManagerDTO profileManager = roomManagerClient.getRoomProfileManagerById(roomId)
        .getBody();

    if (Objects.isNull(profileManager)) {
      return null;
    }
    List<RoomBadgeBackpackDTO> badgeBackpackDTOS = roomBadgeClient.listBadgeBackpackByRoomId(roomId)
        .getBody();
    if(CollectionUtils.isNotEmpty(badgeBackpackDTOS)){

      List<BadgePictureConfigDTO> badgePictureConfigDTOS = sysBadgeConfigService.listBadgePictureByBadgeIds(
          badgeBackpackDTOS.stream().map(RoomBadgeBackpackDTO::getBadgeId)
              .collect(Collectors.toList()));
      if(CollectionUtils.isNotEmpty(badgePictureConfigDTOS)){

        Map<Long, BadgePictureConfigDTO> badgePictureConfigMap = badgePictureConfigDTOS.stream()
            .collect(Collectors.toMap(BadgePictureConfigDTO::getBadgeConfigId, v -> v));

        List<UseRoomBadgeDTO> useRoomBadgeDTOS = badgeBackpackDTOS.stream().map(badge -> {
          return getUseBadges(badge, badgePictureConfigMap);
        }).collect(Collectors.toList());
        profileManager.setUseBadges(useRoomBadgeDTOS);
      }
    }
    return new RoomProfileManagerCO()
        .setProfile(profileManager)
        .setUserProfile(userProfileClient.getByUserId(profileManager.getUserId()).getBody());
  }


  public UseRoomBadgeDTO getUseBadges(RoomBadgeBackpackDTO roomBadgeBackpackDTO,Map<Long, BadgePictureConfigDTO> badgePictureConfigMap){
    UseRoomBadgeDTO useRoomBadgeDTO=new UseRoomBadgeDTO();
    useRoomBadgeDTO.setId(roomBadgeBackpackDTO.getId());
    useRoomBadgeDTO.setUserId(roomBadgeBackpackDTO.getUserId());
    useRoomBadgeDTO.setExpireTime(roomBadgeBackpackDTO.getExpireTime().getTime());
    BadgePictureConfigDTO badgePictureConfigDTO = badgePictureConfigMap.get(
        roomBadgeBackpackDTO.getBadgeId());
    useRoomBadgeDTO.setBadgeName(badgePictureConfigDTO.getBadgeName());
    useRoomBadgeDTO.setBadgeKey(badgePictureConfigDTO.getBadgeKey());
    useRoomBadgeDTO.setSelectUrl(badgePictureConfigDTO.getSelectUrl());
    useRoomBadgeDTO.setType(badgePictureConfigDTO.getType());
    return useRoomBadgeDTO;
  }


  @Override
  public void updateProfile(RoomProfileDTO roomProfile) {

    Boolean result = roomManagerClient.updateSelectiveProfile(roomProfile).getBody();

    if (Boolean.TRUE.equals(result) && Objects.equals(roomProfile.getEvent(), RoomEventEnum.CLOSE.name())) {

      imGroupClient.sendMessageBroadcast(
          BroadcastGroupMsgBodyCmd
              .builder()
              .type(GroupMessageTypeEnum.SYS_CLOSE_ROOM)
              .data(Map.of("roomId", roomProfile.getId()))
              .toPlatform(SysOriginPlatformEnum.valueOf(roomProfile.getSysOrigin()))
              .build()
      );
    }
  }

  @Override
  public List<RoomTouristCO> listRecentVisitors(RoomTouristQryCmd qryCmd) {
    List<RoomTouristDTO> list = roomTouristClient.listRecentVisitors(qryCmd.getRoomId(),
        qryCmd.getUserId()).getBody();
    if (CollectionUtils.isEmpty(list)) {
      return Lists.newArrayList();
    }
    Map<Long, UserProfileDTO> userMap = userProfileClient
        .mapByUserIds(list.stream().map(RoomTouristDTO::getUserId).collect(Collectors.toSet()))
        .getBody();
    if (CollectionUtils.isEmpty(userMap)) {
      return Lists.newArrayList();
    }

    return list.stream().map(log -> new RoomTouristCO()
            .setUserProfile(userMap.get(log.getUserId()))
            .setCreateTime(log.getCreateTime())).filter(Objects::nonNull)
        .collect(Collectors.toList());
  }

  @Override
  public List<OnlineRoomCO> listOnlineRoom(AppActiveVoiceRoomQryCmd qryCmd) {

    List<ActiveVoiceRoomDTO> activeVoiceRooms = activeVoiceRoomClient.listOps(qryCmd).getBody();

    if (CollectionUtils.isEmpty(activeVoiceRooms)) {
      return CollectionUtils.newArrayList();
    }

    Set<Long> roomIds = activeVoiceRooms.stream().map(ActiveVoiceRoomDTO::getId)
        .collect(Collectors.toSet());
    Map<Long, RoomProfileDTO> roomProfileManagerMap = roomManagerClient.mapProfileByRoomIds(
        roomIds).getBody();

    if (CollectionUtils.isEmpty(roomProfileManagerMap)) {
      return CollectionUtils.newArrayList();
    }

    return activeVoiceRooms.stream()
        .map(activeRoom -> new OnlineRoomCO()
            .setProfile(roomProfileManagerMap.get(activeRoom.getId()))
            .setActiveRoom(activeRoom)
        ).collect(Collectors.toList());
  }

  @Override
  public List<OnlineUserDTO> listOnlineMember(String sessionId, Long lastTimingId) {
    return userOnlineClient.flowSessionOnlineUser(sessionId,
            UserOnlineStatusEnum.LANGUAGE_HALL
            , lastTimingId)
        .getBody();
  }

  @Override
  public RoomProfileDTO getRoomProfileByAccount(String sysOrigin, String account) {
    return Optional.ofNullable(userProfileClient.getByAccount(sysOrigin, account))
        .map(ResultResponse::getBody)
        .map(userProfile -> roomManagerClient.getProfileByUserId(userProfile.getId()))
        .map(ResultResponse::getBody)
        .orElse(null);
  }

  @Override
  public List<RoomProfileDTO> listRoomProfileByAccount(String account) {

    List<UserProfileDTO> userProfiles = userProfileClient.getByAccount(account).getBody();
    if (CollectionUtils.isEmpty(userProfiles)) {
      return Lists.newArrayList();
    }

    return roomManagerClient.listByIds(
        userProfiles.stream().map(UserProfileDTO::getId).collect(
            Collectors.toSet())
    ).getBody();
  }

  @Override
  public void removeOrPullBlackUser(RoomRemoveOrPullBlackUserCmd cmd) {

    RoomRemoveUserEventEnum event = RoomRemoveUserEventEnum.valueOf(cmd.getEvent());

    RoomProfileDTO roomProfile = getRoomProfileByAccount(cmd.getSysOrigin(),
        cmd.getRoomAccount());
    ResponseAssert.notNull(RoomErrorCode.ROOM_NOT_EXISTS, roomProfile);

    UserProfileDTO userProfile = userProfileClient.getByAccount(cmd.getSysOrigin(),
        cmd.getUserAccount()).getBody();
    ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);

    ResponseAssert.isTrue(ConsoleErrorCode.SYS_ORIGIN_NOT_EQ,
        Objects.equals(userProfile.getOriginSys(), cmd.getSysOrigin()));

    if (Objects.equals(event, RoomRemoveUserEventEnum.SYS_REMOVE_ROOM_PULL_BLACK_USER)) {
      //系统将用户移出房间黑名单
      Boolean unBanGroupMemberRes = imGroupClient.unBanGroupMember(
          new GroupUnbanCmd()
              .setGroupId(Objects.toString(roomProfile.getRoomAccount()))
              .setUserId(userProfile.getId())
      ).getBody();

      if (Objects.equals(unBanGroupMemberRes, Boolean.TRUE)) {
        roomUserBlacklistClient.remove(roomProfile.getId(), userProfile.getId());
      }
      return;
    }

    if (Objects.equals(event, RoomRemoveUserEventEnum.SYS_REMOVE_ROOM_USER)) {
      //移除房间内的指定用户
      trtcClient.removeUser(
          new TrtcRemoveUserCmd()
              .setRoomId(Long.valueOf(roomProfile.getRoomAccount()))
              .setUserIds(List.of(userProfile.getId()))
              .setLogOrigin("Console removeOrPullBlackUser")
      );
    }

    if (Objects.equals(event, RoomRemoveUserEventEnum.SYS_PULL_BLACK_ROOM_USER)) {
      // 拉黑房间内的指定用户
      roomUserBlacklistClient.add(new RoomUserBlacklistDTO()
          .setTimingId(IdWorker.getId())
          .setSysOrigin(roomProfile.getSysOrigin())
          .setUserId(userProfile.getId())
          .setRoomId(roomProfile.getId())
          .setCreateUserRoles("SYSTEM_OPERATION")
          .setCreateUser(cmd.getUpdateUser())
          .setExpiredTime(TimestampUtils.nowPlusYear(3))
      );
    }

    //发送消息
    newsletterClient.send(
        new NewsletterResultCmd()
            .setUserIds(List.of(userProfile.getId()))
            .setEvent(NewsletterEvent.valueOf(cmd.getEvent()))
            .setData(
                Map.of("userId", userProfile.getId()
                    , "roomId", roomProfile.getId())
            )
    );

  }

  @Override
  public PageResult<RoomApprovalCO> pageRoomApproval(ApprovalConsolePageQryCmd qryCmd) {

    if (Objects.nonNull(qryCmd.getRoomId())) {

      RoomProfileDTO roomProfile = roomManagerClient.getById(qryCmd.getRoomId()).getBody();

      if (Objects.isNull(roomProfile)) {
        return PageResult.newPageResult(qryCmd.getPageQuery().getLimit());
      }

      if (Objects.nonNull(qryCmd.getUserId())
          && !Objects.equals(qryCmd.getUserId(), roomProfile.getUserId())) {
        return PageResult.newPageResult(qryCmd.getPageQuery().getLimit());
      }

      qryCmd.setUserId(roomProfile.getUserId());
    }

    PageResult<ApprovalUserSettingDataDTO> pageResult = approvalUserSettingDataClient.listOps(
        roomProfileManagerAppConvertor.toApprovalOpsPageQryCmd(qryCmd)).getBody();

    if (pageResult.checkRecordsEmpty()) {
      return pageResult.emptyRecords();
    }

    Map<Long, UserProfileDTO> userProfileMap = userProfileClient
        .mapByUserIds(pageResult.getRecords().stream()
            .map(ApprovalUserSettingDataDTO::getUserId).collect(Collectors.toSet()))
        .getBody();

    Map<Long, RoomProfileDTO> roomProfileV2Map = roomManagerClient.mapProfileByUserIds(
        pageResult.getRecords().stream()
            .map(ApprovalUserSettingDataDTO::getUserId).collect(Collectors.toSet())
    ).getBody();

    PageResult<RoomApprovalCO> pageResultCo = pageResult.convert(approval -> {
      UserProfileDTO userProfile = userProfileMap.get(approval.getUserId());
      RoomProfileDTO roomProfile = roomProfileV2Map.get(approval.getUserId());

      if (Objects.isNull(roomProfile)) {
        return null;
      }

      return new RoomApprovalCO()
          .setRoomId(roomProfile.getId())
          .setUserId(approval.getUserId())
          .setUserBaseInfo(userProfile)
          .setRoomAccount(roomProfile.getRoomAccount())
          .setRoomCover(roomProfile.getRoomCover())
          .setRoomDesc(roomProfile.getRoomDesc())
          .setRoomName(roomProfile.getRoomName())
          .setApproveType(approval.getApproveType())
          .setApproveStatus(approval.getApproveStatus())
          .setMachineLabel(approval.getMachineLabel())
          .setNotPassSize(approval.getNotPassSize())
          .setUpdateTime(approval.getUpdateTime());
    });

    pageResultCo.setRecords(
        pageResultCo.getRecords().stream().filter(Objects::nonNull).toList()
    );

    return pageResultCo;
  }

  @Override
  public List<RoomUserBlacklistCO> listRoomUserBlacklist(RoomBlacklistQryCmd qryCmd) {
    var blacklists = roomUserBlacklistClient.listOps(qryCmd)
        .getBody();
    if (CollectionUtils.isEmpty(blacklists)) {
      return Lists.newArrayList();
    }

    var userProfileMap = userProfileClient.mapByUserIds(
        Stream.of(
                blacklists.stream().map(RoomUserBlacklistDTO::getUserId).collect(Collectors.toList()),
                blacklists.stream().map(RoomUserBlacklistDTO::getCreateUser)
                    .collect(Collectors.toList()))
            .flatMap(Collection::stream)
            .collect(Collectors.toSet())).getBody();

    var roomProfileMap = roomManagerClient.mapProfileByRoomIds(
            blacklists.stream().map(RoomUserBlacklistDTO::getRoomId).collect(Collectors.toSet()))
        .getBody();

    return blacklists.stream().map(black -> new RoomUserBlacklistCO()
        .setId(black.getTimingId())
        .setRoomId(black.getRoomId())
        .setCreateUserRoles(black.getCreateUserRoles())
        .setExpiredTime(black.getExpiredTime())
        .setCreateTime(black.getCreateTime())
        .setBeUserProfile(userProfileMap.get(black.getUserId()))
        .setUserProfile(userProfileMap.get(black.getCreateUser()))
        .setRoomProfile(roomProfileMap.get(black.getRoomId()))).collect(Collectors.toList());
  }

  @Override
  public ResultResponse<Void>  updateProfileTools(UserRoomRegionUpdateCmd cmd) {
    ResultResponse<RoomProfileDTO> response = roomManagerClient.getProfileByUserId(cmd.getUserId());
    if (Objects.isNull(response)) {
      return ResultResponse.failure(RoomErrorCode.ROOM_NOT_EXISTS);
    }
    ResultResponse<SysCountryCodeDTO> countryCode = countryCodeService.getSysCountryCodeById(cmd.getCountryId());
    if (Objects.isNull(countryCode)) {
      return ResultResponse.failure(RoomErrorCode.ROOM_NOT_EXISTS);
    }
    RoomProfileDTO roomProfile = response.getBody();
    roomProfile.setCountryCode(countryCode.getBody().getAlphaTwo());
    roomProfile.setCountryName(countryCode.getBody().getAliasName());

    this.updateProfile(roomProfile);

    return ResultResponse.success();
  }
}
