package com.red.circle.console.app.service.app.user;

import com.red.circle.common.business.core.enums.ReceiptType;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.PageUserIdCmd;
import com.red.circle.console.app.convertor.WalletAppConvertor;
import com.red.circle.console.app.dto.clienobject.user.BeanBalanceCO;
import com.red.circle.console.app.dto.clienobject.user.UserBeanIncomeExpenditureCO;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.inner.asserts.ImErrorCode;
import com.red.circle.other.inner.endpoint.sys.ApiOperationLogClient;
import com.red.circle.other.inner.model.cmd.sys.SysOperationIncomeExpenditureCmd;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.wallet.inner.endpoint.wallet.WalletBeanClient;
import com.red.circle.wallet.inner.model.cmd.AddOrSubtractBeansCmd;
import com.red.circle.wallet.inner.model.cmd.BeanReceiptCmd;
import com.red.circle.wallet.inner.model.cmd.UserBeanIncomeExpenditurePageQryCmd;
import com.red.circle.wallet.inner.model.dto.BeanBalanceDTO;
import com.red.circle.wallet.inner.model.dto.WalletReceiptDTO;
import com.red.circle.wallet.inner.model.enums.AppCurrencyTypeEnum;
import com.red.circle.wallet.inner.model.enums.BeanOrigin;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;


/**
 * <p>
 * 用户豆子余额 服务实现类.
 * </p>
 *
 * @author zongpubin on 2023-06-15 16:02
 */
@RequiredArgsConstructor
@Service
public class UserBeanBalanceServiceImpl implements
    UserBeanBalanceService {

  private final WalletBeanClient walletBeanClient;
  private final UserProfileClient userProfileClient;
  private final WalletAppConvertor walletAppConvertor;
  private final ApiOperationLogClient operationLogClient;

  /**
   * 用户豆子余额列表.
   */
  @Override
  public PageResult<BeanBalanceCO> page(PageUserIdCmd cmd) {
    PageResult<BeanBalanceDTO> userBeanBalancePage = ResponseAssert.requiredSuccess(
        walletBeanClient.pageBeanBalance(cmd));
    PageResult<BeanBalanceCO> pageResult = userBeanBalancePage.convert(
        walletAppConvertor::toBeanBalanceCO);
    if (CollectionUtils.isEmpty(userBeanBalancePage.getRecords())) {
      return pageResult;
    }

    Map<Long, UserProfileDTO> userBaseInfoKv = ResponseAssert.requiredSuccess(
        userProfileClient.mapByUserIds(
            pageResult.getRecords().stream().map(BeanBalanceCO::getUserId).collect(
                Collectors.toSet())));

    return pageResult.convert(userBeanBalance -> {
      userBeanBalance.setUserBaseInfo(userBaseInfoKv.get(userBeanBalance.getUserId()));
      userBeanBalance.setBalance(
          userBeanBalance.getEarnPoints().subtract(userBeanBalance.getConsumptionPoints())
              .setScale(0, RoundingMode.DOWN));
      return userBeanBalance;
    });
  }

  /**
   * 用户豆子流水列表.
   */
  @Override
  public PageResult<UserBeanIncomeExpenditureCO> runningWaterPage(
      UserBeanIncomeExpenditurePageQryCmd query) {

    PageResult<UserBeanIncomeExpenditureCO> pageResult = ResponseAssert.requiredSuccess(
            walletBeanClient.pageRunningWater(query))
        .convert(walletAppConvertor::toUserBeanIncomeExpenditureCO);

    if (CollectionUtils.isEmpty(pageResult.getRecords())) {
      return pageResult;
    }

    Map<Long, UserProfileDTO> userBaseInfoKv = ResponseAssert.requiredSuccess(
        userProfileClient.mapByUserIds(
            pageResult.getRecords().stream().map(UserBeanIncomeExpenditureCO::getUserId)
                .collect(Collectors.toSet())));

    Map<String, String> remarksMap = ResponseAssert.requiredSuccess(
        operationLogClient.mapAssociateRemarks(
            pageResult.getRecords().stream()
                .map(UserBeanIncomeExpenditureCO::getAssociateId).collect(
                    Collectors.toSet())));

    return pageResult.convert(userBeanIe -> {
      userBeanIe.setRemarks(remarksMap.get(userBeanIe.getAssociateId()));
      userBeanIe.setUserBaseInfo(userBaseInfoKv.get(userBeanIe.getUserId()));
      return userBeanIe;
    });
  }

  /**
   * 添加或扣除豆子.
   */
  @Override
  public void addOrSubtractBeans(AddOrSubtractBeansCmd param) {

    UserProfileDTO userProfile = ResponseAssert.requiredSuccess(
        userProfileClient.getByUserId(param.getUserId()));
    ResponseAssert.notNull(ImErrorCode.NOT_FOUND_USER_INFO, userProfile);

    String associateId = IdWorkerUtils.getIdStr();

    BeanOrigin beanOriginEnum = Objects.equals(param.getType(), 0)
        ? BeanOrigin.REWARD_COINS : BeanOrigin.DEDUCT_COINS;

    WalletReceiptDTO receipt = walletBeanClient.changeBalance(
        new BeanReceiptCmd()
            .setConsumeId(associateId)
            .setTrackId(associateId)
            .setType(ReceiptType.toEnum(param.getType()))
            .setUserId(userProfile.getId())
            .setSysOrigin(SysOriginPlatformEnum.valueOf(userProfile.getOriginSys()))
            .setOrigin(beanOriginEnum)
    ).getBody();

    ResponseAssert.requiredSuccess(operationLogClient.addSysOperationIncome(
            new SysOperationIncomeExpenditureCmd()
                .setUserId(userProfile.getId())
                .setAssociateId(associateId)
                .setQuantity(param.getQuantity())
                .setBalance(receipt.getBalance())
                .setType(param.getType())
                .setReason(param.getReason())
                .setRemarks(param.getRemark())
                .setCurrencyType(AppCurrencyTypeEnum.BEAN.name())
        )
    );
  }

}
