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

import com.mongodb.client.model.Filters;
import com.red.circle.component.mongodb.config.MongoPrimaryService;
import com.red.circle.other.infra.database.mongo.dto.TemporaryActivityCountParam;
import com.red.circle.other.infra.database.mongo.entity.activity.TemporaryActivityCount;
import com.red.circle.other.infra.database.mongo.service.activity.TemporaryActivityCountService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
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 2022/4/25
 */
@Service
@RequiredArgsConstructor
public class TemporaryActivityCountServiceImpl implements TemporaryActivityCountService {

  private final MongoTemplate mongoTemplate;
  private final MongoPrimaryService mongoPrimaryService;


  private boolean existsPrimary(String id) {
    return mongoPrimaryService.exists("temporary_activity_count", Filters.eq("_id", id));
  }

  @Override
  public void incr(TemporaryActivityCountParam param) {
    if (Objects.isNull(param)) {
      return;
    }
    if (existsPrimary(param.objectId())) {
      mongoTemplate.updateFirst(Query.query(
              Criteria.where("id").is(param.objectId())),
          new Update().inc("quantity", param.getQuantity()),
          TemporaryActivityCount.class);
      return;
    }
    mongoTemplate.save(new TemporaryActivityCount()
        .setId(param.objectId())
        .setSysOrigin(param.getSysOrigin())
        .setUserId(param.getUserId())
        .setActivityType(param.getActivityType())
        .setCountType(param.getCountType())
        .setQuantity(param.getQuantity())
        .setUpdateTime(TimestampUtils.now())
        .setExpiredTime(TimestampUtils.nowPlusDays(40 - (LocalDate.now().getDayOfMonth() - 1)))
    );
  }

  @Override
  public void incrBatch(List<TemporaryActivityCountParam> params) {
    if (CollectionUtils.isEmpty(params)) {
      return;
    }
    mongoTemplate
        .bulkOps(BulkOperations.BulkMode.UNORDERED, TemporaryActivityCount.class)
        .upsert(params.stream()
            .map(count -> Pair.of(
                Query.query(Criteria.where("id").is(count.objectId())),
                new Update()
                    .set("id", count.objectId())
                    .set("sysOrigin", count.getSysOrigin())
                    .set("userId", count.getUserId())
                    .set("activityType", count.getActivityType())
                    .set("countType", count.getCountType())
                    .inc("quantity", count.getQuantity())
                    .set("updateTime", TimestampUtils.now())
                    .set("expiredTime",
                        TimestampUtils.nowPlusDays(40 - (LocalDate.now().getDayOfMonth() - 1)))
            )).collect(Collectors.toList()))
        .execute();
  }

  @Override
  public List<TemporaryActivityCount> list(String sysOrigin, String activityType,
      String countType, Integer size) {
    return mongoTemplate.find(Query.query(
                Criteria.where("countType").is(countType)
                    .and("sysOrigin").is(sysOrigin)
                    .and("activityType").is(activityType))
            .with(Sort.by(Sort.Order.desc("quantity")))
            .limit(size)
        , TemporaryActivityCount.class);
  }
}
