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

import com.red.circle.common.business.core.ImageSizeConst;
import com.red.circle.common.business.core.SensitiveWordFilter;
import com.red.circle.common.business.core.enums.DataApprovalTypeEnum;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.other.app.common.account.FamilyAccountShortProduction;
import com.red.circle.other.app.dto.cmd.family.FamilyCreateCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
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.FamilyCreateRules;
import com.red.circle.other.infra.database.rds.entity.family.FamilyLevelConfig;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.approval.ApprovalUserSettingDataService;
import com.red.circle.other.infra.database.rds.service.family.FamilyBaseInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyCreateRulesService;
import com.red.circle.other.infra.database.rds.service.family.FamilyLevelConfigService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyRoleEnum;
import com.red.circle.other.infra.enums.family.FamilyStatusEnum;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.error.WalletErrorCode;
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 org.springframework.stereotype.Component;

/**
 * <p>
 * 创建家族.
 * </p>
 *
 * @author pengshigang
 * @since 2021-07-21
 */
@Component
@RequiredArgsConstructor
public class FamilyCreateExe {

  private final RedisService redisService;
  private final FamilyCommon familyManager;
  private final OssServiceClient ossServiceClient;
  private final WalletGoldClient walletGoldClient;
  private final UserProfileGateway userProfileGateway;
  private final FamilyBaseInfoService familyBaseInfoService;
  private final FamilyMemberInfoService familyMemberInfoService;
  private final FamilyAccountShortProduction shortAccountManager;
  private final FamilyCreateRulesService familyCreateRulesService;
  private final FamilyLevelConfigService familyLevelConfigService;
  private final ApprovalUserSettingDataService approvalUserSettingDataService;

  public Long execute(FamilyCreateCmd cmd) {

    checkParam(cmd);

    existedFamilyUser(cmd);

    FamilyLevelConfig levelConfig = initLevel(cmd);

    try {

      ResponseAssert.isTrue(CommonErrorCode.NOT_REPEATABLE,
          redisService.lock(lockKey(cmd), 30));

      checkCreateWhereAndPayCandy(cmd);

      Long familyId = IdWorkerUtils.getId();

      createFamily(cmd, levelConfig.getId(), familyId);

      addFamilyMember(cmd, familyId);

      sendHonor(cmd, levelConfig);

      addApproveRecord(cmd);

      cacheFamilyLevel(cmd, levelConfig, familyId);

      return familyId;

    } finally {
      redisService.unlock(lockKey(cmd));
    }

  }

  private String lockKey(FamilyCreateCmd cmd) {
    return "FAMILY_CREATE:" + cmd.getReqUserId();
  }

  private void addApproveRecord(FamilyCreateCmd cmd) {

    Long createUserId = cmd.getReqUserId();
    String sysOrigin = cmd.getReqSysOrigin().getOrigin();

    approvalUserSettingDataService.saveOrUpdateApproval(createUserId, sysOrigin,
        DataApprovalTypeEnum.FAMILY_AVATAR);

    approvalUserSettingDataService.saveOrUpdateApproval(createUserId, sysOrigin,
        DataApprovalTypeEnum.FAMILY_NICKNAME);

    approvalUserSettingDataService.saveOrUpdateApproval(createUserId, sysOrigin,
        DataApprovalTypeEnum.FAMILY_NOTICE);
  }

  private void sendHonor(FamilyCreateCmd cmd, FamilyLevelConfig levelConfig) {
    familyManager.sendFamilyHonorToMember(cmd.getReqUserId(),
        levelConfig.getAvatarFrameId(), levelConfig.getBadgeId());
  }

  private void cacheFamilyLevel(FamilyCreateCmd cmd, FamilyLevelConfig levelConfig, Long familyId) {
    familyManager.cacheFamilyLevel(cmd.getReqSysOrigin().getOrigin() + familyId, levelConfig,
        familyId);
  }

  private void addFamilyMember(FamilyCreateCmd cmd, Long familyId) {
    FamilyMemberInfo familyMemberInfo = new FamilyMemberInfo()
        .setId(familyId)
        .setFamilyId(familyId)
        .setSysOrigin(cmd.getReqSysOrigin().getOrigin())
        .setMemberUserId(cmd.getReqUserId())
        .setMemberRole(FamilyRoleEnum.ADMIN.name());
    familyMemberInfo.setUpdateUser(cmd.getReqUserId());
    familyMemberInfoService.save(familyMemberInfo);
    familyManager.addGroup(familyMemberInfo.getFamilyId(), familyMemberInfo.getMemberUserId());
  }

  private void createFamily(FamilyCreateCmd cmd, Long levelConfigId, Long familyId) {
    familyBaseInfoService.save(new FamilyBaseInfo()
        .setId(familyId)
        .setFamilyAccount(shortAccountManager.getFamilyAccount())
        .setFamilyAvatar(ResponseAssert.requiredSuccess(
            ossServiceClient
                .processImgSaveAsCompressZoom(cmd.getFamilyAvatar(), ImageSizeConst.COVER_HEIGHT)
        ))
        .setFamilyName(cmd.getFamilyName())
        .setFamilyNotice(cmd.getFamilyNotice())
        .setFamilyStatus(FamilyStatusEnum.NORMAL.name())
        .setFamilyLevelId(levelConfigId)
        .setSysOrigin(cmd.getReqSysOrigin().getOrigin())
    );
  }

  private FamilyLevelConfig initLevel(FamilyCreateCmd cmd) {
    FamilyLevelConfig levelConfig = familyLevelConfigService
        .getIntiLevel(cmd.getReqSysOrigin().getOrigin());
    ResponseAssert.notNull(DynamicErrorCode.NO_RELATED_INFORMATION_FOUND, levelConfig);
    return levelConfig;
  }

  private void checkCreateWhereAndPayCandy(FamilyCreateCmd cmd) {

    FamilyCreateRules createRules = getCreateRules(cmd);

    if (getUserLevelExperience(cmd) >= createRules.getUserWealthLevel()) {
      return;
    }

    if (getCandyBalance(cmd).compareTo(createRules.getPayCandy()) < 0) {
      ResponseAssert.failure(WalletErrorCode.INSUFFICIENT_BALANCE);
      return;
    }

    //创建家族扣除金币
    consumeCandy(cmd, createRules);

  }

  private void consumeCandy(FamilyCreateCmd cmd, FamilyCreateRules createRules) {
    walletGoldClient.changeBalance(GoldReceiptCmd.builder()
        .appExpenditure()
        .eventId(Objects.toString(createRules.getId()))
        .userId(cmd.getReqUserId())
        .sysOrigin(SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()))
        .origin(GoldOrigin.GOLD_CREATE_FAMILY)
        .amount(createRules.getPayCandy())
        .build());
  }

  private BigDecimal getCandyBalance(FamilyCreateCmd cmd) {
    return ResponseAssert.requiredSuccess(walletGoldClient.getBalance(cmd.getReqUserId()))
        .getDollarAmount();
  }

  private FamilyCreateRules getCreateRules(FamilyCreateCmd cmd) {
    FamilyCreateRules createRules = familyCreateRulesService
        .getFamilyCreateRules(cmd.getReqSysOrigin().getOrigin());
    ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, createRules);
    return createRules;
  }

  private Integer getUserLevelExperience(FamilyCreateCmd cmd) {
    return userProfileGateway.getUserConsumptionLevel(cmd.requireReqSysOriginEnum(),
            cmd.requiredReqUserId())
        .getWealthLevel();
  }

  private void existedFamilyUser(FamilyCreateCmd cmd) {
    ResponseAssert.isNull(FamilyErrorCode.FAMILY_EXISTENCE,
        familyMemberInfoService.getFamilyMemberByUserId(cmd.getReqUserId()));
  }

  private void checkParam(FamilyCreateCmd cmd) {
    ResponseAssert.isFalse(ResponseErrorCode.REQUEST_PARAMETER_ERROR, StringUtils.isBlanks(
        cmd.getFamilyAvatar(), cmd.getFamilyNotice(), cmd.getFamilyName()));
    //敏感词
    ResponseAssert.isFalse(DynamicErrorCode.SENSITIVE_WORD_ERROR, SensitiveWordFilter.checkSensitiveWord(cmd.getFamilyName()));
    ResponseAssert.isFalse(DynamicErrorCode.SENSITIVE_WORD_ERROR, SensitiveWordFilter.checkSensitiveWord(cmd.getFamilyNotice()));
  }

}
