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

import com.red.circle.common.business.core.enums.ApprovalStatusEnum;
import com.red.circle.common.business.core.enums.DataApprovalTypeEnum;
import com.red.circle.common.business.core.enums.DynamicEventTypeEnum;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.common.business.enums.PhotoApprovalStatusEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.ImAccountClient;
import com.red.circle.external.inner.endpoint.message.NewsletterClient;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
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.approval.CensorContent;
import com.red.circle.mq.business.model.event.approval.CensorProfileEvent;
import com.red.circle.mq.business.model.event.dynamic.DynamicEvent;
import com.red.circle.mq.rocket.business.producer.CensorMqMessage;
import com.red.circle.mq.rocket.business.producer.DynamicMqMessage;
import com.red.circle.mq.rocket.business.producer.TaskMqMessage;
import com.red.circle.other.app.dto.clientobject.dynamic.DynamicListCO;
import com.red.circle.other.app.dto.cmd.dynamic.DynamicContentAddCmd;
import com.red.circle.other.app.enums.violation.ViolationTypeEnum;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserConsumptionLevel;
import com.red.circle.other.infra.common.user.UserAccountCommon;
import com.red.circle.other.infra.database.cache.service.other.DynamicCacheService;
import com.red.circle.other.infra.database.rds.entity.approval.ApprovalDynamicContent;
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.DynamicTimeline;
import com.red.circle.other.infra.database.rds.service.approval.ApprovalDynamicContentService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicBlacklistService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicContentService;
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.DynamicTimelineService;
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.DynamicErrorCode;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.sql.Timestamp;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 创建动态内容.
 * </p>
 *
 * @author pengshigang
 * @since 2022-04-11
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicContentAddCmdExe {

  private final RedisService redisService;
  private final ImAccountClient imAccountClient;
  private final CensorMqMessage otherMqMessage;
  private final OssServiceClient ossServiceClient;
  private final DynamicMqMessage dynamicMqMessage;
  private final WalletGoldClient walletGoldClient;
  private final NewsletterClient newsletterClient;
  private final UserRegionGateway userRegionGateway;
  private final DynamicTagService dynamicTagService;
  private final UserProfileGateway userProfileGateway;
  private final DynamicCacheService dynamicCacheService;
  private final DynamicContentService dynamicContentService;
  private final DynamicPictureService dynamicPictureService;
  private final DynamicTimelineService dynamicTimelineService;
  private final DynamicBlacklistService dynamicBlacklistService;
  private final ApprovalDynamicContentService approvalDynamicContentService;
  private final TaskMqMessage taskMqMessage;
  private final UserAccountCommon userAccountCommon;
  private final AdministratorService administratorService;
  private final AdministratorAuthService administratorAuthService;

  public DynamicListCO execute(DynamicContentAddCmd cmd) {

    //校验参数
    checkParameters(cmd);

    Long contentId = IdWorkerUtils.getId();

    //保存动态
    DynamicListCO save = save(cmd, contentId);

    dynamicCacheService.incrUserTodayDynamicCount(cmd.getReqUserId());

    if (CollectionUtils.isEmpty(cmd.getPictures())) {
      return save;
    }

    sendViolationContentMq(cmd);
    return save;
  }

  private void sendViolationContentMq(DynamicContentAddCmd cmd) {
    otherMqMessage.image(new CensorProfileEvent().setUserId(cmd.getReqUserId())
        .setApprovalType(DataApprovalTypeEnum.DYNAMIC_CONTENT).setContents(
            cmd.getPictures().stream().map(picture -> new CensorContent().setId(picture.getId())
                .setContent(picture.getResourceUrl())).toList()));
  }


  public void addApprovalDynamic(DynamicContentAddCmd cmd) {
    // 验证管理员权限
    ViolationTypeEnum violationTypeEnum = ViolationTypeEnum.DELETE_CONTENT;
    ResponseAssert.isTrue(CommonErrorCode.INSUFFICIENT_PERMISSION,
            administratorService.existsAdmin(cmd.getReqUserId()) &&
                    administratorAuthService.existsAuth(cmd.requiredReqUserId(), violationTypeEnum.name()));


    ApprovalDynamicContent dynamicContent = new ApprovalDynamicContent();
    dynamicContent.setUserId(cmd.getReqUserId());
    dynamicContent.setDynamicId(Long.parseLong(cmd.getContent()));
    dynamicContent.setApproveStatus(ApprovalStatusEnum.PENDING.name());
    dynamicContent.setSysOrigin(cmd.requireReqSysOrigin());
    dynamicContent.setCreateTime(TimestampUtils.now());
    dynamicContent.setCreateUser(cmd.getReqUserId());
    approvalDynamicContentService.save(dynamicContent);
  }

  /**
   * 超出限制发送帖子则支付金币
   */
  private void consumeGold(DynamicContentAddCmd cmd, Long contentId) {

    if (Objects.equals(cmd.getReqSysOrigin().getOrigin(), "YOLO")) {
      return;
    }

    //当前用户今天已发动态数量
    Long userSentTodayCount = getUserTodayDynamicCount(cmd);
    if (userSentTodayCount <= 0) {
      return;
    }
    //限制用户每天发送动态的数量
    Long quantityLimit = dynamicCacheService.getSendQuantityLimit();
    ResponseAssert.isFalse(DynamicErrorCode.DYNAMIC_QUANTITY_LIMIT_ERROR, quantityLimit <= 0);
    //超过限额数量后，每条动态按多少金币收费?
    Long dynamicFees = dynamicCacheService.getSendDynamicFees();
    if (userSentTodayCount < quantityLimit) {
      return;
    }
    // 这段代码问彭石刚，为什么阻断
    ResponseAssert.failure(DynamicErrorCode.DYNAMIC_QUANTITY_LIMIT_ERROR);

    // 防止重复触发
    ResponseAssert.isTrue(DynamicErrorCode.REPEATED_SUBMIT,
        redisService.setIfAbsent("DYNAMIC_CONTENT_CREATE:" + cmd.getReqUserId(), 5,
            TimeUnit.SECONDS));

    walletGoldClient.changeBalance(
        GoldReceiptCmd.builder().appExpenditure().userId(cmd.getReqUserId()).eventId(contentId)
            .sysOrigin(cmd.requireReqSysOrigin()).origin(GoldOrigin.SEND_DYNAMIC_PAY_GOLD)
            .amount(ArithmeticUtils.toBigDecimal(dynamicFees)).build());
  }

  private Long getUserTodayDynamicCount(DynamicContentAddCmd cmd) {
    return dynamicCacheService.getUserTodayDynamicCount(cmd.getReqUserId());
  }

  private List<DynamicPicture> validFillParamToEntity(DynamicContentAddCmd cmd, Long contentId) {

    Timestamp date = TimestampUtils.now();
    List<DynamicPicture> pictures = CollectionUtils.newArrayList();

    for (int i = 0; i < cmd.getPictures().size(); i++) {
      var picture = cmd.getPictures().get(i);

      ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
          StringUtils.isNotBlank(picture.getResourceUrl()));

      DynamicPicture dynamicPicture = new DynamicPicture();

      long picId = IdWorkerUtils.getId();
      picture.setId(picId);

      dynamicPicture.setId(picId);
      dynamicPicture.setDynamicId(contentId);
      if (StringUtils.isNotBlank(picture.getResourceUrl())) {
        dynamicPicture.setResourceUrl(ResponseAssert.requiredSuccess(
            ossServiceClient.getAccessUrl(picture.getResourceUrl())));
        dynamicPicture.setMiniResourceUrl(
            ossServiceClient.processImgSaveAsCompressZoom(picture.getResourceUrl(),
                    picture.getResourceUrl().replace(".", "-MINI-DYNAMIC."), 300)
                .getBody());
      }

      if (StringUtils.isBlank(picture.getViolation())) {
        dynamicPicture.setViolation(PhotoApprovalStatusEnum.SUSPECTED.name());
      }
      dynamicPicture.setHeight(picture.getHeight());
      dynamicPicture.setWidth(picture.getWidth());
      dynamicPicture.setCreateTime(date);
      dynamicPicture.setUpdateTime(date);
      dynamicPicture.setSort(i + 1);

      pictures.add(dynamicPicture);
    }

    return pictures;
  }

  private DynamicListCO save(DynamicContentAddCmd cmd, Long contentId) {
    Timestamp timestamp = TimestampUtils.now();
    String regionId = userRegionGateway.getRegionId(cmd.getReqUserId());

    DynamicContent dynamicContent = new DynamicContent()
            .setId(contentId)
            .setSysOrigin(cmd.requireReqSysOrigin())
            .setContent(cmd.getContent())
            .setDel(Boolean.FALSE).setLocation("")
            .setTagId(cmd.getTagId())
            .setCreateUser(cmd.getReqUserId())
            .setCreateTime(timestamp)
            .setLanguageType(cmd.getReqLanguage())
            .setRegion(regionId);
    dynamicContentService.save(dynamicContent);

    if (CollectionUtils.isNotEmpty(cmd.getPictures())) {
      dynamicPictureService.saveBatch(validFillParamToEntity(cmd, contentId));
    }

    dynamicTimelineService.save(
        new DynamicTimeline().setDynamicContentId(contentId).setOwn(Boolean.TRUE)
            .setRegion(regionId).setCreateUser(cmd.getReqUserId()).setCreateTime(timestamp));

    dynamicMqMessage.sendDynamic(IdWorkerUtils.getIdStr(),
        new DynamicEvent().setDynamicContentId(contentId).setUserId(cmd.getReqUserId())
            .setType(DynamicEventTypeEnum.CREATE).setTimestamp(timestamp).setRegion(regionId));

    return convert(dynamicContent);
  }

  private DynamicListCO convert(DynamicContent dynamicContent) {
      DynamicListCO listCO = new DynamicListCO();
      listCO.setDynamicId(dynamicContent.getId());
      listCO.setContent(dynamicContent.getContent());
      listCO.setTagId(dynamicContent.getTagId());
      listCO.setCreateTime(dynamicContent.getCreateTime());
      return listCO;
  }

  /**
   * 校验参数
   */
  private void checkParameters(DynamicContentAddCmd cmd) {
    ResponseAssert.isTrue(DynamicErrorCode.CONTENT_IS_NULL,
            StringUtils.isNotBlank(cmd.getContent()) || CollectionUtils.isNotEmpty(cmd.getPictures()));

    if (CollectionUtils.isNotEmpty(cmd.getPictures())) {
      ResponseAssert.isTrue(DynamicErrorCode.IMAGE_LIMIT_ERROR, cmd.getPictures().size() <= 9);
    }

    if (Objects.nonNull(cmd.getTagId())) {
      ResponseAssert.notNull(DynamicErrorCode.TAG_IS_NULL,
          dynamicTagService.getById(cmd.getTagId()));
    }

    //判断是否为动态黑名单用户，是则不能发动态
    ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION,
        dynamicBlacklistService.exist(cmd.getReqUserId()));
  }

  /**
   * 校验用户财富，魅力等级
   */
  private void checkUserLevel(DynamicContentAddCmd cmd) {

    if (Objects.equals(cmd.getReqSysOrigin().getOrigin(), "YOLO")) {
      return;
    }

    //获得用户魅力,财富等级限制
    Long limitLevel = dynamicCacheService.getSendLevelLimit();
    UserConsumptionLevel userLevel = getConsumptionLevel(cmd);

    ResponseAssert.isTrue(DynamicErrorCode.WEALTH_AND_CHARM_INSUFFICIENT_ERROR,
        userLevel.getCharmLevel() >= limitLevel && userLevel.getWealthLevel() >= limitLevel);
  }

  private UserConsumptionLevel getConsumptionLevel(DynamicContentAddCmd cmd) {
    return userProfileGateway.getUserConsumptionLevel(cmd.requireReqSysOriginEnum(),
        cmd.requiredReqUserId());
  }


}
