package com.red.circle.other.infra.annotation.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.red.circle.common.business.core.SensitiveWordFilter;
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.core.response.PhoneErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.framework.web.props.EnvProperties;
import com.red.circle.framework.web.util.ValidatorUtils;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.rds.entity.user.user.AuthType;
import com.red.circle.other.infra.database.rds.service.user.device.ArchiveDeviceService;
import com.red.circle.other.infra.database.rds.service.user.user.AuthTypeService;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.other.inner.model.cmd.user.UserProfileCmd;
import com.red.circle.tool.core.phone.PhoneNumberUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.model.cmd.user.account.CreateAccountCmd;
import com.red.circle.other.inner.model.cmd.user.account.MobileAuthCmd;
import com.red.circle.other.inner.model.cmd.user.device.AllowDeviceRegisterCmd;
import com.red.circle.other.inner.model.dto.user.account.UserAccountDTO;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 用户注册切面.
 *
 * @author pengliang on 2019/11/27 16:56
 */
@Aspect
@Slf4j
@Component
@RequiredArgsConstructor
public class CreateAccountAspect {

  private final EnvProperties evnProperties;
  private final AuthTypeService authTypeService;
  private final ArchiveDeviceService archiveDeviceService;
  private final RegisterDeviceGateway registerDeviceGateway;
  private final RegisterRewardStreamProducer registerRewardStreamProducer;
  private final CreateAccountExpandProcess createAccountExpandProcess;
  private final CheckRegisterUserProfileProcess checkRegisterUserProfileProcess;

  @Pointcut("@annotation(com.red.circle.other.infra.annotation.CreateAccount)")
  public void userRegisterAspectPointCut() {
  }

  @SneakyThrows
  @Around("userRegisterAspectPointCut()")
  public Object userRegister(ProceedingJoinPoint joinPoint) {
    CreateAccountCmd cmd = getRegisterCmd(joinPoint);
    cmd.changeOpenId();
    checkRegisterUserProfileNickName(cmd);
    checkCreateLimit(cmd);
    generateUserId(cmd);
    checkRegisterUserProfileProcess.process(cmd);

    ResultResponse<UserAccountDTO> result = (ResultResponse<UserAccountDTO>) joinPoint.proceed();
    log.warn("cmd {} result.getBody {}", cmd, result.getBody());
    if (Objects.isNull(cmd.getProfile())) {
      UserProfileCmd userProfile = new UserProfileCmd();
      userProfile.setCountryId(result.getBody().getUserProfile().getCountryId());
      cmd.setProfile(userProfile);
    }
    if (result.checkSuccess() && Objects.nonNull(result.getBody())) {
      registerRewardStreamProducer.publish(
          SysOriginPlatformEnum.valueOf(cmd.requireReqSysOrigin()),
          cmd.requiredReqUserId(),
          cmd.getProfile().getCountryId()
      );
    }

    createAccountExpandProcess.process(cmd);
    return result;
  }

  private void generateUserId(CreateAccountCmd cmd) {
    cmd.setReqUserId(IdWorkerUtils.getId());
  }

  private void checkCreateLimit(CreateAccountCmd cmd) {
    shieldArea(cmd);

    // 2042 设备不可用
    ResponseAssert.isFalse(CommonErrorCode.DEVICE_UNAVAILABLE,
        archiveDeviceService.existsDevice(cmd.getReqImei(), cmd.requireReqSysOrigin()));

    if (evnProperties.isProd()) {
      // 验证设备&ip 是否允许注册
      ResponseAssert.isTrue(CommonErrorCode.REGISTERED_DEVICES_LIMIT,
          registerDeviceGateway.checkAllowDeviceRegister(
              new AllowDeviceRegisterCmd()
                  .setDeviceNo(cmd.getReqImei())
                  .setDeviceLimit(3)
                  .setIp(cmd.getReqIp())
                  .setIpLimit(6)
                  .setSysOrigin(cmd.requireReqSysOrigin())
          )
      );
    }

    if (cmd.checkTypeMobile()) {
      mobileRegisterCheck(cmd.getMobile());
    }

    // 请求参数错误
    if (StringUtils.isBlank(cmd.registerOpenId())) {
      ResponseAssert
          .failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR, "openId is not blank.");
    }
    AuthType authType = authTypeService.getAuthInfo(cmd.registerOpenId());
    // 4023 注册黑名单
    ResponseAssert.isFalse(UserErrorCode.REGISTER_BLACKLIST, isBlacklist(authType));
    // 4019 第三方已注册
    ResponseAssert.isNull(UserErrorCode.SOURCE_REGISTERED, authType);
  }

  private void shieldArea(CreateAccountCmd cmd) {
    if (evnProperties.isProd() && cmd.checkChina()) {
      ResponseAssert.failure(CommonErrorCode.NOT_SUPPORTED_REGION);
    }
  }

  private boolean isBlacklist(AuthType authType) {
    return Objects.nonNull(authType) && Objects.equals(authType.getDel(), Boolean.TRUE);
  }

  private void mobileRegisterCheck(MobileAuthCmd mobileCmd) {
    // 400 请求参数错误
    if (Objects.isNull(mobileCmd) || !ValidatorUtils.validateFastPass(mobileCmd)) {
      ResponseAssert
          .failure(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
              "mobile is null Or required parameter is empty");
    }

    // 手机号码错误
    ResponseAssert.isTrue(PhoneErrorCode.CELLPHONE_ERROR,
        PhoneNumberUtils.isValidNumber(mobileCmd.getPhonePrefix(),
            Objects.toString(mobileCmd.getPhoneNumber())));
  }

  private CreateAccountCmd getRegisterCmd(ProceedingJoinPoint joinPoint) {
    for (Object arg : joinPoint.getArgs()) {
      if (arg instanceof CreateAccountCmd createAccountCmd) {
        return createAccountCmd;
      }
    }
    throw new IllegalArgumentException("User Register is Not found [RegisterCmd]");
  }


  private void checkRegisterUserProfileNickName(CreateAccountCmd cmd) {
    if(ObjectUtil.isNotEmpty(cmd.getProfile())&&ObjectUtil.isNotEmpty(cmd.getProfile().getUserNickname())) {
      //敏感词
      ResponseAssert.isFalse(DynamicErrorCode.SENSITIVE_WORD_ERROR, SensitiveWordFilter.checkSensitiveWord(cmd.getProfile().getUserNickname()));
    }
  }

}
