package com.red.circle.wallet.infra.database.rds.service.diamond.impl;

import com.google.common.collect.Maps;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
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.wallet.infra.convertor.WalletMigrateInfraConvertor;
import com.red.circle.wallet.infra.database.rds.dao.DiamondBalanceDAO;
import com.red.circle.wallet.infra.database.rds.entity.diamond.DiamondBalance;
import com.red.circle.wallet.infra.database.rds.service.diamond.DiamondBalanceService;
import com.red.circle.wallet.inner.model.cmd.UserDiamondBalanceQryCmd;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 用户钻石余额表(20230718) 服务实现类.
 * </p>
 *
 * @author pengshigang on 2023-07-18 16:14
 */
@Service
@RequiredArgsConstructor
public class DiamondBalanceServiceImpl extends BaseServiceImpl<DiamondBalanceDAO, DiamondBalance>
    implements DiamondBalanceService {

  @Override
  public BigDecimal getAvailableBalance(Long userId) {

    return Optional.ofNullable(getDiamondBalance(userId))
        .map(DiamondBalance::getBalance)
        .orElse(BigDecimal.ZERO);
  }

  private boolean exists(Long userId) {
    return Objects.nonNull(getDiamondBalance(userId));
  }

  private DiamondBalance getDiamondBalance(Long userId) {
    return query()
        .eq(DiamondBalance::getUserId, userId)
        .getOne();
  }

  @Override
  public boolean verifyBalance(Long userId, BigDecimal consumeQuantity) {
    return Optional.ofNullable(getDiamondBalance(userId))
        .map(integralBalance -> ArithmeticUtils.gte(integralBalance.getBalance(), consumeQuantity))
        .orElse(Boolean.FALSE);
  }

  @Override
  public boolean inrDiamond(SysOriginPlatformEnum sysOrigin, Long userId, BigDecimal quantity) {

    if (exists(userId)) {
      return update()
          .set(DiamondBalance::getUpdateTime, TimestampUtils.now())
          .set(DiamondBalance::getUpdateUser, userId)
          .setSql("balance=balance+" + quantity)
          .eq(DiamondBalance::getUserId, userId)
          .last(PageConstant.LIMIT_ONE)
          .execute();
    }
    DiamondBalance diamondBalance = new DiamondBalance()
        .setSysOrigin(sysOrigin.name())
        .setUserId(userId)
        .setBalance(quantity);
    diamondBalance.setCreateUser(userId);
    diamondBalance.setCreateTime(TimestampUtils.now());
    return super.save(diamondBalance);

  }

  @Override
  public boolean decrDiamond(SysOriginPlatformEnum sysOrigin, Long userId, BigDecimal quantity) {

    if (exists(userId)) {
      return update()
          .set(DiamondBalance::getUpdateTime, TimestampUtils.now())
          .set(DiamondBalance::getUpdateUser, userId)
          .setSql("balance=balance-" + quantity)
          .eq(DiamondBalance::getUserId, userId)
          .last(PageConstant.LIMIT_ONE)
          .execute();
    }
    DiamondBalance diamondBalance = new DiamondBalance()
        .setUserId(userId)
        // 转为负数
        .setBalance(quantity.negate());
    diamondBalance.setCreateUser(userId);
    diamondBalance.setCreateTime(TimestampUtils.now());
    return super.save(diamondBalance);
  }

  @Override
  public PageResult<DiamondBalance> pageUserDiamondBalance(UserDiamondBalanceQryCmd query) {

    return query()
        .eq(Objects.nonNull(query.getUserId()), DiamondBalance::getUserId, query.getUserId())
        .orderByDesc(DiamondBalance::getUpdateTime)
        .page(query.getPageQuery());
  }

  @Override
  public Map<Long, BigDecimal> mapBalance(List<Long> userIds) {
    if (CollectionUtils.isEmpty(userIds)) {
      return Maps.newHashMap();
    }
    return Optional.ofNullable(
            query().in(DiamondBalance::getUserId, userIds.stream().collect(Collectors.toSet())).list())
        .map(diamondBalances -> diamondBalances.stream()
            .collect(Collectors.toMap(DiamondBalance::getUserId, DiamondBalance::getBalance)))
        .orElseGet(Maps::newHashMap);
  }

}
