package com.red.circle.other.app.command.dynamic.query;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.PageReq;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.dynamic.DynamicListCO;
import com.red.circle.other.app.dto.clientobject.dynamic.DynamicPictureCO;
import com.red.circle.other.app.dto.cmd.dynamic.DynamicLimitCmd;
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.mongo.entity.dynamic.DynamicPopular;
import com.red.circle.other.infra.database.mongo.service.dynamic.DynamicPopularService;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicContent;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicPicture;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicTag;
import com.red.circle.other.infra.database.rds.entity.dynamic.TopDynamic;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicCommentService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicContentService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicLikeService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicPictureService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicTagService;
import com.red.circle.other.infra.database.rds.service.dynamic.TopDynamicService;
import com.red.circle.other.infra.database.rds.service.user.user.UserSubscriptionService;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.model.dto.user.UserSimpleProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;
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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 热门动态内容列表.
 * </p>
 *
 * @author pengshigang
 * @since 2022-04-25
 */
@Component
@RequiredArgsConstructor
public class DynamicPopularQryExe {

  private final UserRegionGateway userRegionGateway;
  private final DynamicTagService dynamicTagService;
  private final TopDynamicService topDynamicService;
  private final UserProfileGateway userProfileGateway;
  private final DynamicLikeService dynamicLikeService;
  private final DynamicContentService dynamicContentService;
  private final DynamicPictureService dynamicPictureService;
  private final DynamicCommentService dynamicCommentService;
  private final DynamicPopularService dynamicPopularService;
  private final UserSubscriptionService userSubscriptionService;
  private final UserProfileAppConvertor userProfileAppConvertor;

  public List<DynamicListCO> execute(DynamicLimitCmd cmd) {
    PageReq pageReq = cmd.getPageReq();

    //热门动态
    List<DynamicPopular> populars = getPopulars(cmd);

    //大于第一页没数据则返回
    if (CollectionUtils.isEmpty(populars) && pageReq.getCursor() > 1) {
      return Lists.newArrayList();
    }

    //置顶动态ID
    List<Long> topDynamicIds = getTopDynamicIds(cmd);

    List<Long> popularsIds = getPopularContentIds(populars);
    //处理置顶动态,移除与热门动态重复值
    popularsIds.removeAll(topDynamicIds);

    List<DynamicContent> resultList = Lists.newArrayList();
    //置顶动态,如果当前页码非第一页则无视置顶动态
    if (pageReq.getCursor() <= 1) {
      resultList.addAll(getHotDynamic(topDynamicIds));
    }
    //处理热门动态列表
    resultList.addAll(getHotDynamic(popularsIds));

    //没有热门动态时，默认列表处理
    if (CollectionUtils.isEmpty(popularsIds)) {
      List<DynamicContent> tmpContentList = getTmpContentList(cmd);
      tmpContentList.removeAll(resultList);
      resultList.addAll(tmpContentList);
    }

    if (CollectionUtils.isEmpty(resultList)) {
      return Lists.newArrayList();
    }

    resultList = resultList.stream().filter(result -> Objects.nonNull(result) &&
        Objects.nonNull(result.getId())).collect(Collectors.toList());
    if (CollectionUtils.isEmpty(resultList)) {
      return Lists.newArrayList();
    }

    Set<Long> tmpContentIds = resultList.stream().map(DynamicContent::getId)
        .collect(Collectors.toSet());

    Set<Long> userIds = getUserIds(resultList);
    if (CollectionUtils.isEmpty(userIds)) {
      return Lists.newArrayList();
    }

    //自己是否已点赞
    Map<Long, Boolean> likeMap = getLikeMap(cmd, tmpContentIds);
    Map<Long, DynamicContent> contentMap = mapDynamicContent(resultList);
    Map<Long, Boolean> subscriptionMap = getSubscriptionMap(cmd, userIds);
    Map<Long, Long> likeQuantityMap = dynamicLikeService.mapLikeQuantity(tmpContentIds);
    Map<Long, DynamicTag> tagMap = dynamicTagService.mapByIds(getTagIds(resultList));
    Map<Long, UserSimpleProfileDTO> userProfileMap = userProfileAppConvertor.convertToSimpleProfiles(userProfileGateway.mapByUserIds(userIds));
    Map<Long, Integer> commentQuantityMap = dynamicCommentService.mapCommentQuantity(tmpContentIds);
    Map<Long, List<DynamicPicture>> pictureMap = dynamicPictureService.mapPreviewGroup(
        tmpContentIds);

    return resultList.stream().map(content -> {

      DynamicContent dynamic = contentMap.get(content.getId());
      if (Objects.isNull(dynamic) || Boolean.TRUE.equals(dynamic.getDel())) {
        return null;
      }
      DynamicListCO result = new DynamicListCO();
      UserSimpleProfileDTO userProfile = userProfileMap.get(dynamic.getCreateUser());
      if (Objects.isNull(userProfile)) {
        return null;
      }
      result.setUserProfile(userProfile);
      processBaseDetails(dynamic, result, pictureMap);
      result.setUserId(userProfile.getId());
      result.setUserAvatar(userProfile.getUserAvatar());
      result.setUserSex(userProfile.getUserSex());
      result.setUserNickname(userProfile.getUserNickname());

      result.setSubscription(getSubscription(subscriptionMap, dynamic));
      result.setLikeStrQuantity(NumUtils.formatLong(likeQuantityMap.get(dynamic.getId())));
      result.setLike(Optional.ofNullable(likeMap.get(dynamic.getId())).orElse(Boolean.FALSE));
      result.setCommentStrQuantity(NumUtils.formatInt(commentQuantityMap.get(dynamic.getId())));
      result.setTop(topDynamicIds.contains(content.getId()));

      DynamicTag tag = tagMap.get(dynamic.getTagId());
      if (Objects.nonNull(tag)) {
        result.setTag(tag.getTag());
        result.setTagId(tag.getId());
      }

      return result;
    }).filter(Objects::nonNull).collect(Collectors.toList());

  }

  private List<DynamicContent> getTmpContentList(DynamicLimitCmd cmd) {
    return dynamicContentService.pageByTimeDesc(cmd.getPageReq(),
        userRegionGateway.getRegionId(cmd.getReqUserId()),
        cmd.requireReqSysOrigin()).getRecords().stream().toList();
  }

  private List<DynamicContent> getHotDynamic(List<Long> contentIds) {

    if (CollectionUtils.isEmpty(contentIds)) {
      return Lists.newArrayList();
    }

    Map<Long, DynamicContent> tmpContentMap = dynamicContentService.mapByIds(contentIds);
    if (CollectionUtils.isEmpty(tmpContentMap)) {
      return Lists.newArrayList();
    }

    return contentIds.stream().map(tmpContentMap::get).collect(Collectors.toList());

  }

  private List<Long> getPopularContentIds(List<DynamicPopular> populars) {
    if (CollectionUtils.isEmpty(populars)) {
      return Lists.newArrayList();
    }
    return populars.stream().map(DynamicPopular::getDynamicId).distinct()
        .collect(Collectors.toList());
  }

  private List<Long> getTopDynamicIds(DynamicLimitCmd cmd) {

    List<TopDynamic> topCaches = topDynamicService.listBySysOrigin(
        SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()));

    if (CollectionUtils.isEmpty(topCaches)) {
      return Lists.newArrayList();
    }
    return topCaches.stream().map(TopDynamic::getDynamicId).distinct()
        .toList();
  }

  private List<DynamicPopular> getPopulars(DynamicLimitCmd cmd) {
    PageReq pageReq = cmd.getPageReq();
    return dynamicPopularService
        .pageDynamic(cmd.getReqSysOrigin().getOrigin(), pageReq.getCursor(), pageReq.getLimit(),
            userRegionGateway.getRegionId(cmd.getReqUserId()));
  }

  private Map<Long, Boolean> getLikeMap(DynamicLimitCmd cmd, Set<Long> contentIds) {
    return dynamicLikeService.mapByContentIdsByUserId(contentIds, cmd.getReqUserId());
  }

  private Boolean getSubscription(Map<Long, Boolean> subscriptionMap, DynamicContent dynamic) {
    return Optional.ofNullable(subscriptionMap.get(dynamic.getCreateUser())).orElse(Boolean.FALSE);
  }

  private Map<Long, Boolean> getSubscriptionMap(DynamicLimitCmd cmd, Set<Long> userIds) {
    return userSubscriptionService.mapIsSubscription(
        cmd.requiredReqUserId(),
        userIds
    );
  }

  private Set<Long> getTagIds(List<DynamicContent> dynamics) {
    return dynamics.stream().map(DynamicContent::getTagId).collect(Collectors.toSet());
  }

  private Set<Long> getUserIds(List<DynamicContent> dynamics) {

    if (CollectionUtils.isEmpty(dynamics)) {
      return Sets.newHashSet();
    }

    return dynamics.stream().map(DynamicContent::getCreateUser)
        .collect(Collectors.toSet());
  }


  private Map<Long, DynamicContent> mapDynamicContent(List<DynamicContent> contents) {

    if (CollectionUtils.isEmpty(contents)) {
      return Maps.newHashMap();
    }
    return contents.stream().collect(Collectors.toMap(DynamicContent::getId, v -> v));

  }

  static void processBaseDetails(DynamicContent dynamic, DynamicListCO result,
      Map<Long, List<DynamicPicture>> pictureMap) {

    result.setDynamicId(dynamic.getId());
    result.setContent(dynamic.getContent());
    result.setCreateTime(dynamic.getCreateTime());

    List<DynamicPicture> pictures = pictureMap.get(dynamic.getId());
    if (CollectionUtils.isEmpty(pictures)) {
      return;
    }
    result.setPictures(pictures.stream().map(picture -> {
      DynamicPictureCO co = new DynamicPictureCO();
      co.setId(picture.getId());
      co.setDynamicId(picture.getDynamicId());
      co.setResourceUrl(picture.getResourceUrl());
      co.setHeight(picture.getHeight());
      co.setWidth(picture.getWidth());
      co.setSort(picture.getSort());
      co.setViolation(picture.getViolation());
      co.setMiniResourceUrl(picture.getMiniResourceUrl());
      return co;
    }).collect(Collectors.toList()));
  }

}
