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

import com.google.common.collect.Lists;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
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.mq.business.model.event.user.CpApplyEvent;
import com.red.circle.mq.rocket.business.producer.UserMqMessageService;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.database.rds.entity.user.user.CpValue;
import com.red.circle.other.infra.database.rds.service.user.user.CpApplyService;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.tool.core.date.TimestampUtils;
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;

/**
 * 处理cp.
 *
 * @author pengliang on 2021/7/13
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ProcessCpApplyCmd {

  private final RedisService redisService;
  private final CpApplyService cpApplyService;
  private final CpValueService cpValueService;
  private final ImMessageClient imMessageClient;
  private final WalletGoldClient walletGoldClient;
  private final UserMqMessageService userMqMessageService;
  private final CpRelationshipService cpRelationshipService;

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

  private void process(ProcessApplyCmd cmd) {
    CpApply cpApply = cpApplyService.getById(cmd.getApplyId());
    // 没有找到映射信息
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_MAPPING_INFO, cpApply);

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

    // CP已存在
    ResponseAssert.isFalse(UserRelationErrorCode.ME_OR_YOU_CP_EXISTED,
        cpRelationshipService.existsCp(
            Lists.newArrayList(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId())));

    // 操作失败
    ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE,
        cpApplyService.changeStatusById(cmd.getApplyId(), getStatus(cmd)));

    if (!isAgree(cmd)) {
      returnGoldCoins(cmd, cpApply);
      imMessageClient.sendMessageText(cpApply.getAcceptApplyUserId().toString(),
          cpApply.getSendApplyUserId().toString(),
          cmd.getApplyText());
      return;
    }

//    GiftConfigDTO cpGift = ResponseAssert.requiredSuccess(
//        giftConfigClient.getPairCpGive(SysOriginPlatformEnum.valueOf(cmd.requireReqSysOrigin()))
//    );
//
//    ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, cpGift);

    refuseStatusWait(cmd, cpApply);
    cpRelationshipService
        .addCp(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId(), createCpValue(),
            cmd.requireReqSysOrigin());

//    giftBackpackClient.incrGiftAndLimit(new GiftBackpackLimitCmd()
//        .setUserId(cpApply.getSendApplyUserId())
//        .setGiftId(cpGift.getId())
//        .setQuantity(1)
//        .setGiftTab(cpGift.getGiftTab())
//        .setLimitContent(cpApply.getAcceptApplyUserId().toString())
//    );

    imMessageClient
        .sendMessageText(cpApply.getAcceptApplyUserId().toString(),
            cpApply.getSendApplyUserId().toString(),
            cmd.getApplyText());
  }

  private void refuseStatusWait(ProcessApplyCmd cmd, CpApply cpApply) {
    cpApplyService.refuseStatusWait(cmd.requiredReqUserId());
    userMqMessageService.cpApplyDelayed(
        new CpApplyEvent()
            .setId(cpApply.getId())
            .setSysOrigin(SysOriginPlatformEnum.valueOf(cmd.requireReqSysOrigin())),
        TimestampUtils.nowPlusMinutes(1));
  }

  private void returnGoldCoins(ProcessApplyCmd cmd, CpApply cpApply) {
    walletGoldClient.changeBalance(GoldReceiptCmd.builder()
        .appIncome()
        .userId(cpApply.getSendApplyUserId())
        .eventId(cpApply.getId())
        .sysOrigin(cmd.requireReqSysOrigin())
        .origin(GoldOrigin.CP_BUILD)
        .amount(cpApply.getApplyConsumeGold())
        .build());
    cpApplyService.changeStatusById(cmd.getApplyId(), CpApplyStatus.REIMBURSE);
  }

  private Long createCpValue() {
    CpValue cpValue = new CpValue()
        .setCpVal(BigDecimal.ZERO);
    cpValueService.save(cpValue);
    return cpValue.getId();
  }

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

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

}
