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

import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.message.ImMessageClient;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
import com.red.circle.other.infra.database.rds.entity.user.user.FriendshipCard;
import com.red.circle.other.infra.database.rds.entity.user.user.GiveFriendshipCardApply;
import com.red.circle.other.infra.database.rds.service.user.user.FriendshipCardService;
import com.red.circle.other.infra.database.rds.service.user.user.GiveFriendshipCardApplyService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.other.inner.asserts.user.UserRelationErrorCode;
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.enums.GoldOrigin;
import java.math.BigDecimal;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 处理用户友谊关系卡.
 *
 * @author pengshigang on 2022/6/13
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ProcessUserCardApplyCmdExe {

  private final RedisService redisService;
  private final ImMessageClient imMessageClient;
  private final WalletGoldClient walletGoldClient;
  private final FriendshipCardService friendshipCardService;
  private final GiveFriendshipCardApplyService giveFriendshipCardApplyService;


  public void execute(ProcessApplyCmd cmd) {
    String key = "USER_CARD_APPLY_PROCESS_" + cmd.getApplyId();
    try {
      ResponseAssert.isTrue(CommonErrorCode.REQUEST_LIMITING, redisService.lock(key, 60));
      process(cmd);
    } finally {
      redisService.unlock(key);
    }
  }

  private void process(ProcessApplyCmd cmd) {

    GiveFriendshipCardApply apply = giveFriendshipCardApplyService.getById(cmd.getApplyId());

    // 没有找到映射信息
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, apply);

    // 状态错误
    ResponseAssert.isTrue(CommonErrorCode.STATE_ERROR,
        Objects.equals(apply.getStatus(), CpApplyStatus.WAIT.name()));

    if (!isAgree(cmd)) {

      giveFriendshipCardApplyService
          .changeStatusById(cmd.getApplyId(), CpApplyStatus.REFUSE.name());

      returnGoldCoins(cmd, apply);

      imMessageClient.sendMessageText(apply.getAcceptUserId().toString(),
          apply.getSendUserId().toString(), "cmd.getApplyText()");
      return;
    }

    // 校验是否存在
    ResponseAssert.isFalse(UserRelationErrorCode.CARD_EXISTED, friendshipCardService
        .exist(apply.getCardType(), apply.getAcceptUserId(), apply.getSendUserId()));

    ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE,
        giveFriendshipCardApplyService.changeStatusById(cmd.getApplyId(), getStatus(cmd).name()));

    saveCard(apply);

    imMessageClient.sendMessageText(apply.getAcceptUserId().toString(),
        apply.getSendUserId().toString(), "cmd.getApplyText()");
  }

  private void saveCard(GiveFriendshipCardApply apply) {

    //接收人
    friendshipCardService.save(new FriendshipCard()
        .setCardType(apply.getCardType())
        .setAcceptUserId(apply.getSendUserId())
        .setSendUserId(apply.getAcceptUserId())
        .setFriendshipValue(BigDecimal.ZERO)
        .setInitiate(Boolean.TRUE)
    );

    //发送人
    friendshipCardService.save(new FriendshipCard()
        .setCardType(apply.getCardType())
        .setAcceptUserId(apply.getAcceptUserId())
        .setSendUserId(apply.getSendUserId())
        .setFriendshipValue(BigDecimal.ZERO)
        .setInitiate(Boolean.FALSE)
    );
  }


  private void returnGoldCoins(ProcessApplyCmd cmd, GiveFriendshipCardApply apply) {
    walletGoldClient.changeBalance(GoldReceiptCmd.builder()
        .appIncome()
        .userId(apply.getSendUserId())
        .eventId(apply.getId())
        .sysOrigin(cmd.requireReqSysOrigin())
        .origin(GoldOrigin.USER_FRIENDSHIP_CARD_REFUND)
        .amount(apply.getCardGold())
        .build());
  }

  private boolean isAgree(ProcessApplyCmd cmd) {
    return Objects.equals(cmd.getAgree(), Boolean.TRUE);
  }

  private CpApplyStatus getStatus(ProcessApplyCmd cmd) {
    return isAgree(cmd)
        ? CpApplyStatus.AGREE : CpApplyStatus.REFUSE;
  }

}
