package com.red.circle.other.app.command.pet;

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.app.AppIdLongCmd;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.common.pet.PetCommon;
import com.red.circle.other.app.dto.clientobject.pet.PetIncomeCO;
import com.red.circle.other.infra.database.rds.entity.pet.PetIncomeReceive;
import com.red.circle.other.infra.database.rds.entity.pet.PetStage;
import com.red.circle.other.infra.database.rds.entity.pet.PetUserPetBag;
import com.red.circle.other.infra.database.rds.entity.pet.PetUserPetIncomeDetails;
import com.red.circle.other.infra.database.rds.enums.pet.PetIncomeType;
import com.red.circle.other.infra.database.rds.service.pet.PetIncomeReceiveService;
import com.red.circle.other.infra.database.rds.service.pet.PetStageService;
import com.red.circle.other.infra.database.rds.service.pet.PetUserPetBagService;
import com.red.circle.other.infra.database.rds.service.pet.PetUserPetIncomeDetailsService;
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.tool.core.sequence.IdWorkerUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletBeanClient;
import com.red.circle.wallet.inner.model.cmd.BeanReceiptCmd;
import com.red.circle.wallet.inner.model.dto.WalletReceiptDTO;
import com.red.circle.wallet.inner.model.enums.BeanOrigin;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 领取收益.
 *
 * @author pengliang on 2021/10/16
 */
@Component
@RequiredArgsConstructor
public class PetReceiveIncomeCmdExe {

  private final PetCommon petCommon;
  private final PetStageService petStageService;
  private final WalletBeanClient walletBeanClient;
  private final PetUserPetBagService petUserPetBagService;
  private final PetIncomeReceiveService petIncomeReceiveService;
  private final PetUserPetIncomeDetailsService petUserPetIncomeDetailsService;

  public BigDecimal execute(AppIdLongCmd cmd) {
    PetUserPetIncomeDetails incomeDetails = petUserPetIncomeDetailsService.getById(cmd.getId());
    // 2036 领取失败
    ResponseAssert.notNull(CommonErrorCode.RECEIVE_FAIL, incomeDetails);
    ResponseAssert.isTrue(CommonErrorCode.RECEIVE_FAIL,
        Objects.equals(incomeDetails.getReceive(), Boolean.FALSE));
    ResponseAssert.isTrue(CommonErrorCode.RECEIVE_FAIL, incomeDetails.getCanReceiveTime().before(
        TimestampUtils.now()));

    if (Objects.equals(incomeDetails.getUserId(), cmd.getReqUserId())) {
      return chargeBean(cmd, incomeDetails).getBalance();
    }

    BigDecimal stealQuantity = incomeDetails.computedStealQuantity();

    // 2038 没有可偷取内容
    ResponseAssert.isTrue(CommonErrorCode.NO_SUITABLE_CONTENT,
        ArithmeticUtils.gtZero(stealQuantity));

    ResponseAssert.isTrue(CommonErrorCode.NO_SUITABLE_CONTENT,
        petUserPetIncomeDetailsService.updateCasStealQuantity(incomeDetails.getId()
            , stealQuantity
            , incomeDetails.getStealQuantity()));

    WalletReceiptDTO receipt = ResponseAssert.requiredSuccess(
        walletBeanClient.changeBalance(new BeanReceiptCmd()
            .setConsumeId(IdWorkerUtils.getIdStr())
            .setTrackId(Objects.toString(cmd.getId()))
            .setType(ReceiptType.INCOME)
            .setUserId(cmd.getReqUserId())
            .setSysOrigin(SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()))
            .setOrigin(BeanOrigin.STEAL_BEAN)
            .setAmount(stealQuantity)
        ));

    petIncomeReceiveService.save(new PetIncomeReceive()
        .setIncomeUserId(cmd.getReqUserId())
        .setPetUserId(incomeDetails.getUserId())
        .setPetId(incomeDetails.getPetId())
        .setIncomeDetailsId(incomeDetails.getId())
        .setIncomeQuantity(stealQuantity)
        .setIncomeBalance(incomeDetails.getRemainingQuantity())
        .setType(PetIncomeType.STEAL.name())
    );

    // 2067 操作冲突
    ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT,
        petUserPetIncomeDetailsService.updateVersion(incomeDetails));
    return receipt.getBalance();
  }

  private WalletReceiptDTO chargeBean(AppIdLongCmd cmd,
      PetUserPetIncomeDetails incomeDetails) {
    WalletReceiptDTO receipt = ResponseAssert.requiredSuccess(
        walletBeanClient.changeBalance(new BeanReceiptCmd()
            .setConsumeId(IdWorkerUtils.getIdStr())
            .setTrackId(Objects.toString(cmd.getId()))
            .setType(ReceiptType.INCOME)
            .setUserId(cmd.getReqUserId())
            .setSysOrigin(SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()))
            .setOrigin(BeanOrigin.CHARGE_BEAN)
            .setAmount(incomeDetails.getRemainingQuantity())
        )
    );

    receiveSuccess(incomeDetails);

    petIncomeReceiveService.save(new PetIncomeReceive()
        .setIncomeUserId(incomeDetails.getUserId())
        .setPetUserId(incomeDetails.getUserId())
        .setPetId(incomeDetails.getPetId())
        .setIncomeDetailsId(incomeDetails.getId())
        .setIncomeQuantity(incomeDetails.getRemainingQuantity())
        .setIncomeBalance(incomeDetails.getRemainingQuantity())
        .setType(PetIncomeType.CHARGE.name())
    );
    return receipt;
  }


  private void receiveSuccess(PetUserPetIncomeDetails incomeDetails) {
    // 2036 领取失败
    ResponseAssert.isTrue(CommonErrorCode.RECEIVE_FAIL,
        petUserPetIncomeDetailsService.checkCanReceive(incomeDetails.getId()));

    // 2067 操作冲突
    ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT,
        petUserPetIncomeDetailsService.updateCharged(incomeDetails));

    // 计算收益
    PetUserPetBag petBag = petUserPetBagService.getById(incomeDetails.getPetBagId());
    ResponseAssert.notNull(CommonErrorCode.RECEIVE_FAIL, incomeDetails);
    PetStage petStage = petStageService.getByState(petBag.getPetId(), petBag.getPetStage());
    ResponseAssert.notNull(CommonErrorCode.RECEIVE_FAIL, incomeDetails);

    List<PetUserPetIncomeDetails> petUserPetIncomeDetails = petUserPetIncomeDetailsService
        .listDetailsTwoSize(incomeDetails.getUserId());

    if (petUserPetIncomeDetails.size() >= petStage.getRevenueNum()) {
      return;
    }

    List<PetIncomeCO> petIncomes = petCommon.calculateIncome(petStage);

    if (CollectionUtils.isEmpty(petIncomes)) {
      return;
    }

    List<PetUserPetIncomeDetails> pets = petCommon
        .toListPetUserPetIncomeDetails(petIncomes, petBag);

    if (CollectionUtils.isEmpty(petUserPetIncomeDetails)) {
      petUserPetIncomeDetailsService.saveBatch(pets);
      return;
    }

    petUserPetIncomeDetailsService.save(pets.get(0));
  }
}
