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

import com.red.circle.component.mongodb.page.MongoPageHelper;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.infra.database.mongo.entity.live.RoomContributionCount;
import com.red.circle.other.infra.database.mongo.service.live.RoomContributionCountService;
import com.red.circle.other.inner.enums.live.RoomContributionCountType;
import com.red.circle.other.inner.model.cmd.live.RoomContributionCountPageQryCmd;
import com.red.circle.tool.core.date.LocalDateUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import java.math.BigDecimal;
import java.util.Objects;
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.stereotype.Service;

/**
 * 榜单统计 实现.
 *
 * @author pengshigang on 2022/02/14
 */
@Service
@RequiredArgsConstructor
public class RoomContributionCountServiceImpl implements RoomContributionCountService {

  private final MongoTemplate mongoTemplate;
  private final MongoPageHelper mongoPageHelper;

  private boolean existsData(Long roomId, RoomContributionCountType type) {
    return mongoTemplate
        .exists(Query.query(getUniquenessCriteria(roomId, type)),
            RoomContributionCount.class);
  }

  private Criteria getUniquenessCriteria(Long roomId, RoomContributionCountType type) {
    return Criteria.where("id").is(getUniqueId(roomId, type));
  }

  private String getDateStr(RoomContributionCountType type) {
    if (Objects.equals(type, RoomContributionCountType.DAILY)) {
      return getNowToInteger();
    }
    return getNowWeekMonday();
  }

  /**
   * 获得本周一时间
   */
  private String getNowWeekMonday() {
    return LocalDateUtils.nowWeekMondayToInteger().toString();
  }

  /**
   * 获得当前时间
   */
  private String getNowToInteger() {
    return LocalDateUtils.nowToInteger().toString();
  }

  @Override
  public PageResult<RoomContributionCount> pageOps(RoomContributionCountPageQryCmd query) {
    query.setDefaultDateNumber();

    Criteria criteria = new Criteria();
    if (Objects.nonNull(query.getRoomId())) {
      criteria.and("roomId").is(query.getRoomId());
    }
    criteria.and("type").is(query.getType());
    criteria.and("dateNumber").is(query.getDateNumber());

    return mongoPageHelper.query(new Query(criteria),
        RoomContributionCount.class,
        query.getPageQuery().getLimit(),
        query.getPageQuery().getCursor(),
        Sort.Order.desc("totalQuantity")
    );

  }

  @Override
  public void incrQuantity(String sysOrigin, Long roomId, Long userId, BigDecimal quantity) {

    if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
      return;
    }

    incr(roomId, userId, quantity, sysOrigin, RoomContributionCountType.WEEKLY);
    incr(roomId, userId, quantity, sysOrigin, RoomContributionCountType.DAILY);
  }

  @Override
  public void correctionData(Long roomId, BigDecimal quantity) {

    if (Objects.isNull(roomId) || Objects.isNull(quantity) || quantity.longValue() <= 0) {
      return;
    }

    dealingProblems(roomId, RoomContributionCountType.WEEKLY, quantity);

    dealingProblems(roomId, RoomContributionCountType.DAILY, quantity);

  }

  /**
   * 矫正数据
   */
  private void dealingProblems(Long roomId, RoomContributionCountType type, BigDecimal quantity) {

    RoomContributionCount count = mongoTemplate
        .findOne(Query.query(getUniquenessCriteria(roomId, type)), RoomContributionCount.class);

    if (Objects.isNull(count)) {
      return;
    }

    BigDecimal totalQuantity = count.getTotalQuantity().compareTo(quantity) >= 0 ?
        count.getTotalQuantity().subtract(quantity) : BigDecimal.ZERO;

    mongoTemplate
        .updateFirst(Query.query(Criteria.where("id").is(count.getId())),
            new Update().set("totalQuantity", totalQuantity),
            RoomContributionCount.class);

  }

  /**
   * 累计流水
   */
  private void incr(Long roomId, Long userId, BigDecimal quantity, String sysOrigin,
      RoomContributionCountType type) {
    if (existsData(roomId, type)) {
      mongoTemplate
          .updateFirst(Query.query(getUniquenessCriteria(roomId, type)),
              new Update().inc("totalQuantity", quantity),
              RoomContributionCount.class);
      return;
    }

    addRank(sysOrigin, roomId, userId, type, quantity);
  }


  private void addRank(String sysOrigin, Long roomId, Long userId, RoomContributionCountType type,
      BigDecimal quantity) {

    RoomContributionCount count = new RoomContributionCount();
    count.setId(getUniqueId(roomId, type));
    count.setSysOrigin(sysOrigin);
    count.setType(type);
    count.setUserId(userId);
    count.setRoomId(roomId);
    count.setTotalQuantity(quantity);
    count.setDateNumber(getDateStr(count.getType()));
    count.setWithdrawQuantity(BigDecimal.ZERO);
    count.setCreateTime(TimestampUtils.now());
    mongoTemplate.save(count);
  }

  private String getUniqueId(Long roomId, RoomContributionCountType type) {

    return String.valueOf(roomId)
        .concat("_")
        .concat(type.name())
        .concat("_")
        .concat(getDateStr(type));
  }

}
