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

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.common.business.enums.DynamicMessageEnum;
import com.red.circle.other.app.common.room.DynamicCommon;
import com.red.circle.other.app.dto.cmd.dynamic.DynamicLikeCmd;
import com.red.circle.other.infra.database.cache.service.other.DynamicCacheService;
import com.red.circle.other.infra.database.mongo.service.dynamic.DynamicPopularService;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicCommentLike;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicContent;
import com.red.circle.other.infra.database.rds.entity.dynamic.DynamicMessage;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicCommentLikeService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicContentService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicMessageService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicPictureService;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.num.NumUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 动态-点赞评论.
 * </p>
 *
 * @author pengshigang
 * @since 2022-04-14
 */
@Component
@RequiredArgsConstructor
public class DynamicCommentLikeCmdExe {

  private final DynamicCommon dynamicCommon;
  private final DynamicCacheService dynamicCacheService;
  private final DynamicContentService dynamicContentService;
  private final DynamicPopularService dynamicPopularService;
  private final DynamicCommentLikeService dynamicCommentLikeService;
  private final DynamicMessageService dynamicMessageService;
  private final DynamicPictureService dynamicPictureService;
  private final com.red.circle.component.redis.service.RedisService redisService;

  public Long execute(DynamicLikeCmd cmd) {

    DynamicContent content = checkParams(cmd);
    Long id = IdWorkerUtils.getId();

    if (Boolean.TRUE.equals(cmd.getLike())) {

      ResponseAssert.isFalse(DynamicErrorCode.LIKED, getExist(cmd));
      save(cmd, id);

      // 标记根评论需要更新热度
      markCommentForHotScoreUpdate(cmd.getRootCommentId());

      if (Objects.equals(cmd.getReqUserId(), cmd.getToUserId())) {
        return getIncrQuantity(cmd);
      }
      //热门权重
      updateScore(cmd, content, 1);

      // 保存点赞评论消息
      saveDynamicMessage(cmd, DynamicMessageEnum.LIKE_COMMENT);

      return getIncrQuantity(cmd);
    }

    ResponseAssert.isTrue(DynamicErrorCode.UNLIKED, getExist(cmd));

    deleteCommentLike(cmd);

    // 标记根评论需要更新热度
    markCommentForHotScoreUpdate(cmd.getRootCommentId());

    if (Objects.equals(cmd.getReqUserId(), cmd.getToUserId())) {
      return getDecrQuantity(cmd);
    }
    //热门权重
    updateScore(cmd, content, -1);

    return getDecrQuantity(cmd);
  }

  private Long getDecrQuantity(DynamicLikeCmd cmd) {
    return dynamicCacheService.decrCommentLikeQuantity(cmd.getDynamicId(), cmd.getCommentId());
//    return NumUtils.formatLong(dynamicCacheService.decrCommentLikeQuantity(cmd.getDynamicId(), cmd.getCommentId()));
  }

  private void deleteCommentLike(DynamicLikeCmd cmd) {
    dynamicCommentLikeService
        .delete(cmd.getDynamicId(), cmd.getCommentId(), cmd.getReqUserId());
  }

  private void updateScore(DynamicLikeCmd cmd, DynamicContent content, Integer score) {

    if (!Objects.equals(content.getCreateUser(), cmd.getReqUserId())) {
      dynamicPopularService.updateScore(cmd.getDynamicId(),
          score > 0 ? score * dynamicCacheService.getLikeScore() : 0,
          cmd.getReqSysOrigin().getOrigin(),
          content.getRegion());
    }
  }

  private DynamicContent checkParams(DynamicLikeCmd cmd) {
    ResponseAssert.isFalse(CommonErrorCode.REQUIRED_FIELDS_CANNOT_BE_IGNORED,
        Objects.isNull(cmd.getCommentId()) || Objects.isNull(cmd.getToUserId()));
    DynamicContent dynamicContent = dynamicContentService.getById(cmd.getDynamicId());
    ResponseAssert.notNull(DynamicErrorCode.CONTENT_IS_NULL, dynamicContent);
    ResponseAssert.isFalse(DynamicErrorCode.CONTENT_DELETE, dynamicContent.getDel());
    return dynamicContent;
  }

  private Long getIncrQuantity(DynamicLikeCmd cmd) {
    return dynamicCacheService.incrCommentLikeQuantity(cmd.getDynamicId(), cmd.getCommentId());
//    return NumUtils.formatLong(dynamicCacheService.incrCommentLikeQuantity(cmd.getDynamicId(), cmd.getCommentId()));
  }

  private void save(DynamicLikeCmd cmd, Long id) {
    DynamicCommentLike dynamicLike = new DynamicCommentLike();
    dynamicLike.setId(id);
    dynamicLike.setDynamicCommentId(cmd.getCommentId());
    dynamicLike.setDynamicContentId(cmd.getDynamicId());
    dynamicLike.setCreateUser(cmd.getReqUserId());
    dynamicLike.setRootCommentId(cmd.getRootCommentId());
    dynamicLike.setCreateTime(TimestampUtils.now());
    dynamicCommentLikeService.save(dynamicLike);
  }

  private Boolean getExist(DynamicLikeCmd cmd) {
    return dynamicCommentLikeService
        .exist(cmd.getDynamicId(), cmd.getCommentId(), cmd.getReqUserId());
  }

  private void saveDynamicMessage(DynamicLikeCmd cmd, DynamicMessageEnum type) {
    DynamicMessage message = new DynamicMessage();
    message.setId(IdWorkerUtils.getId());
    message.setDynamicContentId(cmd.getDynamicId());
    message.setDynamicCommentId(cmd.getCommentId());
    message.setContent(dynamicPictureService.getFirstNormalPic(cmd.getDynamicId()));
    message.setType(type.name());
    message.setToUserId(cmd.getToUserId());
    message.setCreateTime(TimestampUtils.now());
    message.setCreateUser(cmd.getReqUserId());
    dynamicMessageService.save(message);
  }

  /**
   * 标记根评论需要更新热度分数
   */
  private void markCommentForHotScoreUpdate(Long rootCommentId) {
    if (rootCommentId == null) {
      return;
    }
    try {
      redisService.setAdd("comment:hot_score:pending", rootCommentId.toString());
    } catch (Exception e) {
      // 标记失败不影响主流程，只记录日志
      // 定时任务会兜底更新
    }
  }

}
