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

import com.red.circle.common.business.core.enums.CommonErrorEnum;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.app.dto.cmd.family.FamilyBaseInfoQueryCmd;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBaseInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBoxUserContribute;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.family.FamilyBaseInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyBoxDailyService;
import com.red.circle.other.infra.database.rds.service.family.FamilyBoxUserContributeService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyBoxConfigEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.tuple.PennyAmount;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.time.LocalDate;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 投入宝箱金币.
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FamilyBoxContributeExe {

  private final FamilyCommon familyCommon;
  private final FamilyMemberInfoService familyMemberInfoService;
  private final FamilyBoxDailyService familyBoxDailyService;
  private final FamilyBoxUserContributeService familyBoxUserContributeService;
  private final WalletGoldClient walletGoldClient;
  private final FamilyBaseInfoService familyBaseInfoService;

  @Transactional(rollbackFor = Exception.class)
  public void execute(FamilyBaseInfoQueryCmd cmd) {

    FamilyMemberInfo memberInfo = familyMemberInfoService.getFamilyMemberByUserId(cmd.getReqUserId());
    ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, memberInfo);

    FamilyBaseInfo info = familyBaseInfoService.getBaseInfoById(cmd.getFamilyId());
    ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, info);
    ResponseAssert.isTrue(CommonErrorEnum.INSUFFICIENT_PERMISSION, Objects.equals(info.getId(), memberInfo.getFamilyId()));

    LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
    
    ResponseAssert.isFalse(FamilyErrorCode.REPEAT_APPLICATION, 
        familyBoxUserContributeService.hasContributed(memberInfo.getFamilyId(), cmd.getReqUserId(), today));

    String recordId = cmd.getReqUserId() + "_" + today;
    consumeGold(cmd.getReqUserId(), cmd.getReqSysOrigin().getOrigin(), recordId);

    familyBoxUserContributeService.save(new FamilyBoxUserContribute()
        .setFamilyId(memberInfo.getFamilyId())
        .setUserId(cmd.getReqUserId())
        .setBoxDate(today)
        .setGoldAmount(FamilyBoxConfigEnum.CONTRIBUTE_GOLD)
        .setSysOrigin(cmd.getReqSysOrigin().getOrigin()));

    familyBoxDailyService.incrementContributeCount(
        memberInfo.getFamilyId(), today, cmd.getReqSysOrigin().getOrigin());
  }

  private void consumeGold(Long userId, String sysOrigin, String recordId) {
    GoldReceiptCmd build = GoldReceiptCmd.builder()
        .appExpenditure()
        .userId(userId)
        .amount(PennyAmount.ofDollar(FamilyBoxConfigEnum.CONTRIBUTE_GOLD.longValue()))
        .eventId(recordId)
        .sysOrigin(SysOriginPlatformEnum.valueOf(sysOrigin))
        .origin(GoldOrigin.FAMILY_BOX_CONTRIBUTE)
        .build();
    ResultResponse<WalletReceiptResDTO> changed = walletGoldClient.changeBalance(build);
    if (!changed.checkSuccess()) {
      throw new RuntimeException("Family box contribute failed to change balance");
    }

  }
}
