package com.red.circle.other.infra.database.mongo.service.user.count.impl;

import com.mongodb.client.model.Filters;
import com.red.circle.component.mongodb.config.MongoPrimaryService;
import com.red.circle.other.infra.database.mongo.entity.user.count.UserGuardCount;
import com.red.circle.other.infra.database.mongo.service.user.count.UserGuardCountService;
import com.red.circle.tool.core.date.TimestampUtils;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;

/**
 * 用户守护 实现.
 *
 * @author pengliang on 2021/11/15
 */
@Service
@RequiredArgsConstructor
public class UserGuardCountServiceImpl implements UserGuardCountService {

  private final MongoTemplate mongoTemplate;
  private final MongoPrimaryService mongoPrimaryService;

  @Override
  public void incrLasts15Days(Long userId, Long guardUserId, Long quantity) {

    if (existsPrimary(userId, guardUserId)) {
      mongoTemplate.updateFirst(Query.query(getUniquenessCriteria(userId, guardUserId)),
          new Update().inc("quantity", quantity),
          UserGuardCount.class);
      return;
    }

    mongoTemplate.save(new UserGuardCount()
        .setId(getUniquenessId(userId, guardUserId))
        .setUserId(userId)
        .setGuardUserId(guardUserId)
        .setQuantity(quantity)
        .setExpiredTime(TimestampUtils.nowPlusDays(15))
    );

    //    mongoTemplate.upsert(Query.query(getUniquenessCriteria(userId, guardUserId)),
    //        getInc(userId, guardUserId, quantity),
    //        UserGuardCount.class);
  }

  private Update getInc(Long userId, Long guardUserId, Long quantity) {
    return new Update()
        .set("id", getUniquenessCriteria(userId, guardUserId))
        .set("userId", userId)
        .set("guardUserId", guardUserId)
        .set("expiredTime", TimestampUtils.nowPlusDays(15))
        .inc("quantity", quantity);
  }

  @Override
  public void incrLasts15Days(Long userId, List<Long> guardUserIds, Long quantity) {

    guardUserIds.forEach(guardUserId -> incrLasts15Days(userId, guardUserId, quantity));

    // TODO 有时间研究一下 bulkOps
    //        mongoTemplate
    //            .bulkOps(BulkOperations.BulkMode.UNORDERED, "user_guard_count")
    //            .upsert(getPair(userId, guardUserIds, quantity))
    //            .execute();

  }

  private List<Pair<Query, Update>> getPair(Long userId, List<Long> guardUserIds,
      Long quantity) {
    return guardUserIds.stream().map(guardUserId -> Pair.of(
            Query.query(getUniquenessCriteria(userId, guardUserId)),
            getInc(userId, guardUserId, quantity)
        )
    ).collect(Collectors.toList());
  }

  @Override
  public List<UserGuardCount> listUserGuardTop(Long guardUserId, Integer topSize) {
    return mongoTemplate
        .find(Query.query(Criteria.where("guardUserId").is(guardUserId))
            .with(Sort.by(Sort.Order.desc("quantity")))
            .limit(topSize), UserGuardCount.class);
  }

  private boolean existsPrimary(Long userId, Long guardUserId) {
    return mongoPrimaryService.exists("user_guard_count",
        Filters.eq("_id", getUniquenessId(userId, guardUserId)));

  }

  private Criteria getUniquenessCriteria(Long userId, Long guardUserId) {
    return Criteria.where("id").is(getUniquenessId(userId, guardUserId));
  }

  public String getUniquenessId(Long userId, Long guardUserId) {
    return userId + "_" + guardUserId;
  }
}
