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

import com.google.common.base.Throwables;
import com.red.circle.common.business.core.enums.ApprovalStatusEnum;
import com.red.circle.common.business.core.enums.DataApprovalTypeEnum;
import com.red.circle.common.business.core.enums.ReceiptType;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.enums.AccountStatusEnum;
import com.red.circle.common.business.enums.DiamondOrigin;
import com.red.circle.component.mq.MessageEventProcess;
import com.red.circle.component.mq.MessageEventProcessDescribe;
import com.red.circle.component.mq.config.RocketMqMessageListener;
import com.red.circle.component.mq.service.Action;
import com.red.circle.component.mq.service.ConsumerMessage;
import com.red.circle.component.mq.service.MessageListener;
import com.red.circle.mq.business.model.event.approval.CensorContent;
import com.red.circle.mq.business.model.event.approval.CensorProfileEvent;
import com.red.circle.mq.business.model.event.user.LoginLoggerEvent;
import com.red.circle.mq.rocket.business.producer.CensorMqMessage;
import com.red.circle.mq.rocket.business.streams.LoginRegisterLoggerSink;
import com.red.circle.other.app.common.invite.InviteCampaignGoClient;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
import com.red.circle.other.domain.model.user.UserConstant;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.mongo.entity.activity.InviteRegisterRecordCount;
import com.red.circle.other.infra.database.mongo.service.activity.InviteActivityCountService;
import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRegister;
import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRewardRecord;
import com.red.circle.other.infra.database.rds.entity.user.user.LatestMobileDevice;
import com.red.circle.other.infra.database.rds.entity.user.user.LoginLogger;
import com.red.circle.other.infra.database.rds.entity.user.user.UserExpand;
import com.red.circle.other.infra.database.rds.service.approval.ApprovalUserSettingDataService;
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;
import com.red.circle.other.infra.database.rds.service.user.user.ExpandService;
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRegisterService;
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRewardRecordService;
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserSummaryService;
import com.red.circle.other.infra.database.rds.service.user.user.LoginLoggerService;
import com.red.circle.other.infra.enums.user.logger.RewardOriginEnum;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.inner.model.cmd.user.IncrDeviceRegisterCmd;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletDiamondClient;
import com.red.circle.wallet.inner.model.cmd.DiamondReceiptCmd;
import java.math.BigDecimal;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 登录日志.
 *
 * @author pengliang on 2023/5/25
 */
@Slf4j
@RocketMqMessageListener(groupId = LoginRegisterLoggerSink.INPUT, tag = LoginRegisterLoggerSink.TAG)
@RequiredArgsConstructor
public class LoginLoggerListener implements MessageListener {

  private final ExpandService expandService;
  private final CensorMqMessage censorMqMessage;
  private final UserProfileGateway userProfileGateway;
  private final LoginLoggerService loginLoggerService;
  private final MessageEventProcess messageEventProcess;
  private final WalletDiamondClient walletDiamondClient;
  private final RegisterDeviceGateway registerDeviceGateway;
  private final EnumConfigCacheService enumConfigCacheService;
  private final InviteUserSummaryService inviteUserSummaryService;
  private final InviteCampaignGoClient inviteCampaignGoClient;
  private final LatestMobileDeviceService latestMobileDeviceService;
  private final InviteUserRegisterService inviteUserRegisterService;
  private final InviteActivityCountService inviteActivityCountService;
  private final InviteUserRewardRecordService inviteUserRewardRecordService;
  private final ApprovalUserSettingDataService approvalUserSettingDataService;
  private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService;

  @Override
  public Action consume(ConsumerMessage message) {
    return messageEventProcess.consume(
        MessageEventProcessDescribe.builder()
            .logTag("登录注册")
            .consumeMsgTimeoutMinute(30)
            .repeatConsumeMinute(1)
            .repeatConsumeTag("LoginLog")
            .checkConsumeTag(LoginRegisterLoggerSink.TAG)
            .message(message)
            .build(),
        LoginLoggerEvent.class,
        eventBody -> {
          log.info("login logger event:{}", JacksonUtils.toJson(eventBody));
          if (Objects.equals(eventBody.getEventType(), 1)) {
            processLogin(eventBody);
            return;
          }
          if (Objects.equals(eventBody.getEventType(), 0)) {
            processRegister(eventBody);
          }
        }
    );

  }


  private void processLogin(LoginLoggerEvent event) {
    UserProfile userProfile = userProfileGateway.getByUserId(event.getUserId());

    if (Objects.isNull(userProfile)) {
      log.warn("processLogin log error, user not found [{}].", event.getUserId());
      return;
    }

    // 保存日志
    saveLoginLogger(event);

    // 账号不可用冻结状态
    if (AccountStatusEnum.isArchive(userProfile.getAccountStatus()) ||
        AccountStatusEnum.isFreeze(userProfile.getFreezingTime())) {
      return;
    }

    // 最新设备登记信息
    latestMobileDeviceService.saveLatestMobileDevice(toLatestMobileDevice(event));

    // 更新最近活跃时间
    expandService.updateLastActiveTime(event.getUserId());
  }

  public void processRegister(LoginLoggerEvent event) {
    registerDeviceGateway.incrRegisterQuantityAsync(new IncrDeviceRegisterCmd()
        .setDeviceNo(event.getImei())
        .setIp(event.ipNullDefault())
        .setSysOrigin(event.getSysOrigin())
    );
    var userProfile = userProfileGateway.getByUserId(event.getUserId());

    if (Objects.isNull(userProfile)) {
      log.warn("processLogin log error, user not found [{}].", event.getUserId());
      return;
    }
    expandService.notExistsCreate(
        new UserExpand()
            .setUserId(event.getUserId())
            .setLanguage(event.getLanguage())
            .setRegisterCountryCode(userProfile.getCountryCode())
    );
    approvalProfile(userProfile);
    processLogin(event);
    handleInviteCampaignCode(event);
    handleInvitePeople(event);
  }

  private void approvalProfile(UserProfile userProfile) {
    // 头像审核
    censorMqMessage.image(new CensorProfileEvent()
        .setUserId(userProfile.getId())
        .setApprovalType(DataApprovalTypeEnum.AVATAR)
        .addContent(new CensorContent()
            .setId(userProfile.getId())
            .setContent(userProfile.getUserAvatar())
        ));

    // 初始化审批扩展-NICKNAME
    approvalUserSettingDataService
        .saveApproval(userProfile.getId(),
            userProfile.getOriginSys(),
            DataApprovalTypeEnum.NICKNAME,
            UserConstant.isRandomNickname(userProfile.getUserNickname())
                ? ApprovalStatusEnum.NONE : ApprovalStatusEnum.PENDING);
  }

  private void handleInviteCampaignCode(LoginLoggerEvent event) {
    String invitationCode = Objects.toString(event.getInvitationCode(), "").trim();
    if (invitationCode.isEmpty()) {
      return;
    }
    if (Objects.isNull(event.getUserId()) || Objects.toString(event.getSysOrigin(), "").trim()
        .isEmpty()) {
      log.warn("invite campaign register bind skipped, missing userId or sysOrigin. event={}",
          JacksonUtils.toJson(event));
      return;
    }

    try {
      InviteCampaignGoClient.RegisterBindCodeResponse response = inviteCampaignGoClient.bindRegisterCode(
          new InviteCampaignGoClient.RegisterBindCodeRequest()
              .setInviteCode(invitationCode)
              .setSysOrigin(event.getSysOrigin())
              .setInviteeUserId(event.getUserId())
              .setClientIp(Objects.toString(event.getIp(), ""))
              .setDeviceFingerprint(Objects.toString(event.getImei(), "")));
      log.info("invite campaign register bind result, userId={}, inviteCode={}, response={}",
          event.getUserId(), invitationCode, JacksonUtils.toJson(response));
    } catch (Exception ex) {
      log.warn("invite campaign register bind failed, userId={}, inviteCode={}",
          event.getUserId(), invitationCode, ex);
    }
  }

  private void handleInvitePeople(LoginLoggerEvent event) {
    log.warn("event {}", event);
    if (Objects.isNull(event.getInvitePeople())) {
      return;
    }

    if (inviteUserRegisterService.existsByInviteUserId(event.getUserId())) {
      return;
    }

    if (inviteUserRegisterService.existsByDeviceId(event.getImei())) {
      return;
    }

    UserProfile invitePeopleProfile = userProfileGateway.getByAccount(
        event.getSysOrigin(),
        event.getInvitePeople());

    if (Objects.isNull(invitePeopleProfile)) {
      return;
    }

    //保存邀请关系
    inviteUserRegisterService.save(new InviteUserRegister()
        .setSysOrigin(event.getSysOrigin())
        .setUserId(invitePeopleProfile.getId())
        .setInviteUserId(event.getUserId())
        .setDeviceId(event.getImei())
        .withCreateUser(event.getUserId()));

    //累计邀请人数
    inviteUserSummaryService.incrUser(invitePeopleProfile.getId(), 1);

    handleVoiceInvitePeople(invitePeopleProfile.getId(), event);

    if (Objects.equals(Boolean.FALSE,
        businessDevelopmentBaseInfoService.checkBD(invitePeopleProfile.getId())
    )) {
      // BD不能参邀请活动
      inviteActivityCountService.add(new InviteRegisterRecordCount()
          .setId(IdWorkerUtils.getIdStr())
          .setQuantity(0L)
          .setToUserId(event.getUserId())
          .setUserId(invitePeopleProfile.getId())
          .setDeviceNo(latestMobileDeviceService.getImeiByUserId(invitePeopleProfile.getId()))
      );
    }
  }

  private void handleVoiceInvitePeople(Long invitePeopleUserId, LoginLoggerEvent event) {
    if (inviteUserRewardRecordService.existsByInviteUserId(event.getUserId())) {
      log.warn("已领取过奖励信息:{}", event.getUserId());
      return;
    }

    BigDecimal diamondQuantity = enumConfigCacheService.getValueBigDecimal(
        EnumConfigKey.INVITED_NEW_USER_REWARD,
        event.getSysOrigin());

    inviteUserRewardRecordService.save(
        new InviteUserRewardRecord()
            .setSysOrigin(event.getSysOrigin())
            .setUserId(invitePeopleUserId)
            .setInviteUserId(event.getUserId())
            .setOrigin(RewardOriginEnum.INVITE_REGISTER.name())
            .setOriginName(RewardOriginEnum.INVITE_REGISTER.getDesc())
            .setQuantity(diamondQuantity)
    );

    if (ArithmeticUtils.lteZero(diamondQuantity)) {
      log.warn("没有获取到有效的奖励:{}", diamondQuantity);
      return;
    }

    walletDiamondClient.changeBalanceAsync(new DiamondReceiptCmd()
        .setConsumeId(IdWorkerUtils.getIdStr())
        .setSysOrigin(SysOriginPlatformEnum.valueOf(event.getSysOrigin()))
        .setTrackId(IdWorkerUtils.getId())
        .setUserId(invitePeopleUserId)
        .setOriginUserId(event.getUserId())
        .setType(ReceiptType.INCOME)
        .setOrigin(DiamondOrigin.INVITED_NEW_USER_REWARD)
        .setAmount(diamondQuantity)
        .setCreateTime(event.getReqTime())
    );

  }


  private void saveLoginLogger(LoginLoggerEvent event) {
    if (Objects.nonNull(event.getAuthType())) {
      try {
        loginLoggerService.save(new LoginLogger()
            .setId(IdWorkerUtils.getId())
            .setDeviceId(event.getImei())
            .setUserId(event.getUserId())
            .setIp(event.ipNullDefault())
            .setLoginType(event.getAuthType())
            .setAppVersion(event.getAppVersion())
            .setAppPlatform(event.getRequestClient())
            .setSysVersion(event.getAppPhoneSysVersion())
            .setSysModel(event.getAppPhoneModel())
            .setCreateTime(TimestampUtils.now())
        );
      } catch (Exception ex) {
        log.warn("数据异常[1]：{}, {}", Throwables.getStackTraceAsString(ex),
            JacksonUtils.toJson(event));
      }
      return;
    }
    log.warn("数据异常[2]：{}", JacksonUtils.toJson(event));
  }

  private LatestMobileDevice toLatestMobileDevice(LoginLoggerEvent event) {
    return new LatestMobileDevice()
        .setUserId(event.getUserId())
        .setLanguage(event.getLanguage())
        .setZoneId(event.getZoneId())
        .setIp(event.ipNullDefault())
        .setImei(event.getImei())
        .setRequestClient(event.getRequestClient())
        .setPhoneModel(event.getAppPhoneModel())
        .setPhoneSysVersion(event.getAppPhoneSysVersion())
        .setBuildVersion(event.getAppBuildVersion())
        .setAppVersion(event.getAppVersion())
        .setSysOrigin(Objects.toString(event.getSysOrigin()));
  }


}
