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

import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.infra.database.mongo.entity.activity.InviteExtractRecordCount;
import com.red.circle.other.infra.database.mongo.entity.activity.InviteRegisterRecordCount;
import com.red.circle.other.infra.database.mongo.service.activity.InviteActivityCountService;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.stereotype.Service;


/**
 * 邀请活动统计.
 *
 * @author pengshigang on 2022/9/9
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InviteActivityCountServiceImpl implements InviteActivityCountService {

  private final MongoTemplate mongoTemplate;

  @Override
  public void add(InviteRegisterRecordCount count) {

    InviteRegisterRecordCount recordCount = mongoTemplate
        .findOne(Query.query(Criteria.where("toUserId").is(count.getToUserId())
                .orOperator(Criteria.where("deviceNo").is(count.getDeviceNo()))),
            InviteRegisterRecordCount.class);

    if (Objects.nonNull(recordCount)) {
      log.warn("邀请活动-重复邀请同一设备号: data:{}", JacksonUtils.toJson(count));
      return;
    }

    count.setExpiredTime(TimestampUtils.nowPlusDays(60));
    count.setCreateTime(TimestampUtils.now());
    mongoTemplate.save(count);
  }

  @Override
  public void inc(Long toUserId, Long quantity) {

    InviteRegisterRecordCount recordCount = mongoTemplate
        .findOne(Query.query(Criteria.where("toUserId").is(toUserId)),
            InviteRegisterRecordCount.class);
    if (Objects.isNull(recordCount)) {
      return;
    }

    mongoTemplate.updateFirst(Query.query(Criteria.where("id").is(recordCount.getId())),
        new Update().inc("quantity", quantity),
        InviteRegisterRecordCount.class);
  }

  @Override
  public List<InviteRegisterRecordCount> list(Long userId) {

    return mongoTemplate
        .find(Query.query(Criteria.where("userId").is(userId))
            .with(Sort.by(Sort.Order.desc("quantity"))), InviteRegisterRecordCount.class);

  }

  @Override
  public List<InviteRegisterRecordCount> list(Long userId, Long toUserId, LocalDateTime startTime,
      LocalDateTime endTime) {
    Criteria criteria = new Criteria();
    if (Objects.nonNull(userId)) {
      criteria.and("userId").is(userId);
    }

    if (Objects.nonNull(toUserId)) {
      criteria.and("toUserId").is(toUserId);
    }

    if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
      criteria.andOperator(
          Criteria.where("createTime").gte(startTime),
          Criteria.where("createTime").lte(endTime)
      );
    }
    return mongoTemplate
        .find(Query.query(criteria)
            .with(Sort.by(Sort.Order.desc("createTime")))
            .limit(200), InviteRegisterRecordCount.class);
  }

  @Override
  public void addExtract(Long userId, Long quantity, String sysOrigin) {

    ResponseAssert.isNull(CommonErrorCode.NON_REPEATABLE, mongoTemplate
        .findOne(Query.query(Criteria.where("userId").is(userId)),
            InviteExtractRecordCount.class));

    mongoTemplate.save(new InviteExtractRecordCount()
        .setId(userId.toString())
        .setUserId(userId)
        .setSysOrigin(sysOrigin)
        .setQuantity(quantity)
        .setExpiredTime(TimestampUtils.nowPlusDays(60))
        .setCreateTime(TimestampUtils.now())
    );
  }

  @Override
  public List<InviteExtractRecordCount> listExtract(String sysOriginName) {

    return mongoTemplate.find(Query.query(Criteria.where("sysOrigin").is(sysOriginName))
            .with(Sort.by(Sort.Order.desc("quantity"))),
        InviteExtractRecordCount.class);
  }
}
