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

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.app.dto.cmd.family.FamilyBoxClaimCmd;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBoxDaily;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBoxUserReward;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
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.FamilyBoxUserRewardService;
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 FamilyBoxClaimExe {

  private final FamilyMemberInfoService familyMemberInfoService;
  private final FamilyBoxDailyService familyBoxDailyService;
  private final FamilyBoxUserContributeService familyBoxUserContributeService;
  private final FamilyBoxUserRewardService familyBoxUserRewardService;
  private final WalletGoldClient walletGoldClient;

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

    FamilyBoxConfigEnum config = FamilyBoxConfigEnum.getByLevel(cmd.getLevel());
    ResponseAssert.notNull(CommonErrorCode.DATA_ERROR, config);

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

    LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();

    ResponseAssert.isTrue(FamilyErrorCode.BOX_NOT_UNLOCKED,
        familyBoxUserContributeService.hasContributed(memberInfo.getFamilyId(), cmd.getReqUserId(), today));

    FamilyBoxDaily dailyRecord = familyBoxDailyService.getByFamilyAndDate(memberInfo.getFamilyId(), today);
    Integer contributeCount = Objects.nonNull(dailyRecord) ? dailyRecord.getContributeCount() : 0;
    
    ResponseAssert.isTrue(FamilyErrorCode.BOX_NOT_UNLOCKED, contributeCount >= config.getRequiredCount());

    ResponseAssert.isFalse(FamilyErrorCode.BOX_ALREADY_CLAIMED, 
        familyBoxUserRewardService.hasClaimed(memberInfo.getFamilyId(), cmd.getReqUserId(), today, cmd.getLevel()));

    String recordId = cmd.getReqUserId() + "_" + today + "_" + cmd.getLevel();
    addUserGold(cmd.getReqUserId(), cmd.getReqSysOrigin().getOrigin(), config.getRewardGold(), recordId);

    familyBoxUserRewardService.save(new FamilyBoxUserReward()
        .setFamilyId(memberInfo.getFamilyId())
        .setUserId(cmd.getReqUserId())
        .setBoxDate(today)
        .setLevel(cmd.getLevel())
        .setRewardGold(config.getRewardGold())
        .setSysOrigin(cmd.getReqSysOrigin().getOrigin()));
  }

  private void addUserGold(Long userId, String sysOrigin, Integer amount, String recordId) {
    GoldReceiptCmd build = GoldReceiptCmd.builder()
        .appIncome()
        .userId(userId)
        .amount(PennyAmount.ofDollar(amount.longValue()))
        .eventId(recordId)
        .sysOrigin(SysOriginPlatformEnum.valueOf(sysOrigin))
        .origin(GoldOrigin.FAMILY_BOX_REWARD)
        .build();

    ResultResponse<WalletReceiptResDTO> changed = walletGoldClient.changeBalance(build);
    if (!changed.checkSuccess()) {
        throw new RuntimeException("Family box claim failed to change balance");
    }
  }
}
