
package com.red.circle.other.infra.common.user;

import com.google.common.collect.Lists;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.infra.database.rds.entity.user.user.*;
import com.red.circle.other.infra.database.rds.enums.CacheKeysEnum;
import com.red.circle.other.infra.database.rds.service.user.user.*;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.DateUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.convertor.user.RedPacketInviteInfraConvertor;
import com.red.circle.other.infra.convertor.user.UserProfileInfraConvertor;
import com.red.circle.other.infra.database.cache.entity.user.InviteUserRedPacketCarouselAwardsCache;
import com.red.circle.other.infra.database.cache.entity.user.InviteUserRedPacketConfigCache;
import com.red.circle.other.infra.database.cache.service.user.RedPacketInviteUserCacheService;
import com.red.circle.other.infra.database.rds.dto.user.InviteNewWithdrawalDTO;
import com.red.circle.other.infra.database.rds.dto.user.InviteUserCheckAuthDTO;
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 邀请用户红包.
 *
 * @author pengshigang
 * @since 2023-12-20
 */
@Component
@RequiredArgsConstructor
public class RedPacketInviteUserCommon {
  private final RedisService redisService;
  private final WalletGoldClient walletGoldClient;
  private final UserRegionGateway userRegionGateway;
  private final UserProfileGateway userProfileGateway;
  private final InviteConfigService inviteConfigService;
  private final UserProfileInfraConvertor userProfileInfraConvertor;
  private final LatestMobileDeviceService latestMobileDeviceService;
  private final InviteRedPacketHelpService inviteRedPacketHelpService;
  private final InviteCarouselAwardsService inviteCarouselAwardsService;
  private final InviteRedPacketRecordService inviteRedPacketRecordService;
  private final RedPacketInviteInfraConvertor redPacketInviteInfraConvertor;
  private final RedPacketInviteUserCacheService redPacketInviteUserCacheService;
  private final InviteWithdrawTransitBalanceService inviteWithdrawTransitBalanceService;

  /**
   * 获得临时提现账户余额.
   */
  public InviteNewWithdrawalDTO getWithdrawTransitBalance(Long userId, String sysOrigin) {
    InviteNewWithdrawalDTO withdrawalCO = new InviteNewWithdrawalDTO();
    withdrawalCO.setQuantity(BigDecimal.ZERO);
    withdrawalCO.setShowButton(Boolean.FALSE);

    InviteWithdrawTransitBalance balance = getWithdrawTransitBalance(userId);
    if (Objects.nonNull(balance)) {
      withdrawalCO.setQuantity(balance.getIncomeAmount().subtract(balance.getExpenditureBalance()));
    }

    InviteUserRedPacketConfigCache config = getInviteConfig(sysOrigin);
    if (Objects.nonNull(config)) {
      withdrawalCO.setShowButton(Boolean.FALSE.equals(config.getCheckClose())
          && withdrawalCO.getQuantity().compareTo(BigDecimal.ZERO) > 0);
    }
    return withdrawalCO;
  }

  /**
   * 校验用户开红包权限.
   */
  public InviteUserCheckAuthDTO getUserCheckAuth(Long userId, String inviteCode) {

    UserProfile userProfile = userProfileGateway.getByUserId(userId);

    InviteUserCheckAuthDTO authDTO = initGameInviteUserCheckAuthDTO(userProfile);

    InviteUserRedPacketConfigCache redPacketConfig = getInviteConfig(userProfile.getOriginSys());
    if (Objects.isNull(redPacketConfig)) {
      return authDTO;
    }

    authDTO.setClosed(redPacketConfig.getCheckClose());
    if (Boolean.TRUE.equals(authDTO.getClosed())) {
      return authDTO;
    }

    // 校验是否支持区域
    if (StringUtils.isNotBlank(redPacketConfig.getRegionCodeArray()) &&
            !(Arrays.asList(redPacketConfig.getRegionCodeArray().split(","))
                    .contains(userRegionGateway.getRegionCode(userId)))) {
      authDTO.setClosed(Boolean.TRUE);
      return authDTO;
    }

    LatestMobileDevice latestMobileDevice = getMobileDeviceServiceByUserId(userId);
    checkUserLatestMobileDevice(latestMobileDevice);
    authDTO.setIp(latestMobileDevice.getIp());
    authDTO.setImei(latestMobileDevice.getImei());

    // 已集满N次则不能继续开红包
    boolean a1 = inviteRedPacketRecordService.getCompleteCount(userId)
            >= redPacketConfig.getTotalFrequency();

    // 一天集满N次则不能继续开红包
    boolean a2 = inviteRedPacketRecordService.getCompleteCount(userId,
            ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()) >= redPacketConfig.getDayFrequency();

    // 一个设备集满N次则不能继续开红包
    boolean a3 = inviteRedPacketRecordService.getCompleteCountByImei(latestMobileDevice.getImei(),userProfile.getOriginSys())
            >= redPacketConfig.getDeviceFrequency();

    // 一个ip集满N次则不能继续开红包
    boolean a4 = inviteRedPacketRecordService.getCompleteCountByIp(latestMobileDevice.getIp(),userProfile.getOriginSys())
            >= redPacketConfig.getIpFrequency();
    InviteRedPacketRecord inviteRedPacketRecord = inviteRedPacketRecordService.getUserRedPacketByUndone(userId);
    long time = Objects.nonNull(userProfile.getCreateTime()) ? TimestampUtils.durationNowDays(
            userProfile.getCreateTime()) : 1L;
    //如果显示有参加活动的红包显示红包入口
    if (redPacketConfig.getGoldCoinBalance().compareTo(BigDecimal.ZERO) != 0
            && ResponseAssert.requiredSuccess(walletGoldClient.getBalance(userId)).getDollarAmount().compareTo(redPacketConfig.getGoldCoinBalance()) < 1
            && time>=1
            && Objects.isNull(inviteRedPacketRecord)
    ) {
      InviteNewWithdrawalDTO cameInvite=getWithdrawTransitBalance(userProfile.getId(),userProfile.getOriginSys());
      if(!cameInvite.getShowButton()){
        authDTO.setClosed(Boolean.TRUE);
      }
      return authDTO;
    }

    if(redPacketConfig.getRegDateMax()!=0 && redPacketConfig.getRegDateMax()>time &&time>=1){
      authDTO.setClosed(Boolean.TRUE);
      return authDTO;
    }
    authDTO.setShowInviteRedPacket(!(a1 || a2 || a3 || a4));
    authDTO.setBayWindow(redPacketConfig.getBayWindow());
    authDTO.setRemovableRedPacket(
            Objects.isNull(inviteRedPacketRecord));

    if (StringUtils.isBlank(inviteCode)) {
      return authDTO;
    }
    if (Objects.equals(userProfile.getAccount(), inviteCode)) {
      return authDTO;
    }

    UserProfile inviteUserProfile = getByAccount(inviteCode, userProfile);
    if (Objects.isNull(inviteUserProfile)) {
      return authDTO;
    }
    authDTO.setInviteCodeEffective(Boolean.TRUE);
    authDTO.setInviter(userProfileInfraConvertor.toUserRunProfile(inviteUserProfile));
    return authDTO;

  }


  private Integer getRedisUserCount(String key){
    Integer number= redisService.getStringToInteger(key);
    if(Objects.isNull(number)){
      number=0;
    }
    return number;
  }

  private Integer getRedisUserCountDays(Long userId){
    Integer number=  redisService.getStringToInteger(CacheKeysEnum.THE_NUMBER_OF_RED_ENVELOPES_COLLECTED_TODAY.getAppendKey(userId));
    if(Objects.isNull(number)){
      number=0;
    }
    return number;
  }

  private InviteUserCheckAuthDTO initGameInviteUserCheckAuthDTO(UserProfile userProfile) {
    InviteUserCheckAuthDTO authDTO = new InviteUserCheckAuthDTO();
    authDTO.setClosed(Boolean.TRUE);
    authDTO.setShowHelpTis(Boolean.FALSE);
    authDTO.setRemovableRedPacket(Boolean.FALSE);
    authDTO.setShowInviteRedPacket(Boolean.FALSE);
    authDTO.setInviteCodeEffective(Boolean.FALSE);
    authDTO.setBayWindow(Boolean.TRUE);
    authDTO.setThisAccount(userProfile.getAccount());
    return authDTO;
  }

  private void checkUserLatestMobileDevice(LatestMobileDevice latestMobileDevice) {
    ResponseAssert.notNull(CommonErrorCode.DEVICE_UNAVAILABLE, latestMobileDevice);
    ResponseAssert.isFalse(CommonErrorCode.DEVICE_UNAVAILABLE, StringUtils.isBlank(
        latestMobileDevice.getIp()) || StringUtils.isBlank(latestMobileDevice.getImei()));
  }

  private LatestMobileDevice getMobileDeviceServiceByUserId(Long userId) {
    return latestMobileDeviceService.getByUserId(userId);
  }

  private UserProfile getByAccount(String inviteCode, UserProfile userProfile) {
    return userProfileGateway.getByAccount(userProfile.getOriginSys(),
        inviteCode);
  }

  /**
   * 获得提现账户.
   */
  public InviteWithdrawTransitBalance getWithdrawTransitBalance(Long userId) {
    if (Objects.isNull(userId)) {
      return null;
    }
    return inviteWithdrawTransitBalanceService.getById(userId);
  }

  /**
   * 获得转盘奖项配置模版.
   */
  public List<InviteUserRedPacketCarouselAwardsCache> listCarouselAwardsConfig(String sysOrigin) {

    List<InviteCarouselAwards> awards = inviteCarouselAwardsService.listBySysOrigin(sysOrigin);
    if (CollectionUtils.isEmpty(awards)) {
      return Lists.newArrayList();
    }

    return redPacketInviteUserCacheService.listCarouselAwardsCache(sysOrigin,
        () -> redPacketInviteInfraConvertor.toRedPacketInviteCarouselAwardsCacheList(awards));

  }


  /**
   * 获得配置.
   */
  public InviteUserRedPacketConfigCache getInviteConfig(String sysOrigin) {

    InviteConfig inviteConfig = inviteConfigService.getBySysOrigin(sysOrigin);
    if (Objects.isNull(inviteConfig)) {
      return null;
    }

    return redPacketInviteUserCacheService.getConfigCache(
        sysOrigin, () -> redPacketInviteInfraConvertor.toRedPacketInviteConfigCache(inviteConfig));
  }

  /**
   * 校验是否为回归用户,是则同时助力(true, 可以)
   */
  public Boolean checkReturnUserAndHelp(Long userId, Long toUserId, Timestamp lastActiveTime) {

    LatestMobileDevice mobileDevice = latestMobileDeviceService.getByUserId(userId);
    if (checkLatestMobileDevice(mobileDevice)) {
      return Boolean.FALSE;
    }
    if(getInvitedCountryCode(toUserId)){
      updateViolationOrNotStatus(toUserId);
      return Boolean.FALSE;
    }

    // 回归用户校验
    if (DateUtils.toDurationDays(lastActiveTime, DateUtils.now()) < 60) {
      return Boolean.FALSE;
    }

    // 进行助力次数增加
    List<Long> helpUserIds = redPacketInviteUserCacheService.getReturnUserHelp(userId);
    if (CollectionUtils.isNotEmpty(helpUserIds)) {
      // 对应时间已经助力过,不能再次助力
      return Boolean.FALSE;
    }
    // 助力一次
    redPacketInviteUserCacheService.cacheReturnUserHelp(userId, toUserId);
    return Boolean.TRUE;

  }

  /**
   * 校验新用户是否可以助力他人,能则同时助力(true 可以).
   *
   * @param userId   助力人
   * @param toUserId 被助力人
   */
  public Boolean checkNewUserAndHelp(Long userId, Long toUserId) {

    UserProfile userProfile = userProfileGateway.getByUserId(userId);
    if (Objects.isNull(userProfile)) {
      return Boolean.FALSE;
    }

    Timestamp userRegisterTime = userProfile.getCreateTime();
    LatestMobileDevice mobileDevice = latestMobileDeviceService.getByUserId(userId);
    if (checkLatestMobileDevice(mobileDevice)) {
      return Boolean.FALSE;
    }

    if(getInvitedCountryCode(toUserId)){
      updateViolationOrNotStatus(toUserId);
      return Boolean.FALSE;
    }

    InviteUserRedPacketConfigCache redPacketConfig = getInviteConfig(mobileDevice.getSysOrigin());
    if (Objects.isNull(redPacketConfig)) {
      return Boolean.FALSE;
    }

    if(getToUserTime(toUserId,redPacketConfig)){
      return Boolean.FALSE;
    }

    // 新用户助力点
    List<Long> days = getNewUserHelpDays(redPacketConfig);
    if (CollectionUtils.isEmpty(days)) {
      return Boolean.FALSE;
    }
    for (Long day : days) {
      // 可助力的时间
      long startTime = DateUtils.plusDays(userRegisterTime, day.intValue() - 1).getTime();
      long endTime = DateUtils.plusDays(userRegisterTime, day.intValue()).getTime();
      // 当前时间
      long nowTime = DateUtils.now().getTime();
      if (nowTime >= startTime && nowTime <= endTime) {
        return help(userId, toUserId, day);
      }
    }
    return Boolean.FALSE;
  }


  private Boolean getToUserTime(Long toUserId, InviteUserRedPacketConfigCache redPacketConfig ){
    UserProfile toUserIdProifle = userProfileGateway.getByUserId(toUserId);
    long time = Objects.nonNull(toUserIdProifle.getCreateTime()) ? TimestampUtils.durationNowDays(
            toUserIdProifle.getCreateTime()) : 1L;
    //如果余额不够则不能被助力
    if (time<1
            &&redPacketConfig.getGoldCoinBalance().compareTo(BigDecimal.ZERO) != 0
            && ResponseAssert.requiredSuccess(walletGoldClient.getBalance(toUserId)).getDollarAmount().compareTo(redPacketConfig.getGoldCoinBalance()) < 1
    ){
      return Boolean.TRUE;
    }

    return Boolean.FALSE;
  }

  /**
   * 判断被邀请人国家是否来自10个不同国家
   * @param userId
   * @return
   */
  private Boolean getInvitedCountryCode(Long userId)
  {
    List<UserProfile> userProfiles = userProfileGateway.listByUserIds(
            inviteRedPacketHelpService.getInviteUserIdList(userId));
    List<String> countryCodeList = userProfiles.stream()
            .map(UserProfile::getCountryCode)
            .distinct()
            .toList();
    //邀请人邀请人是否超过10个国家
    if(countryCodeList.size()>=10){
      return Boolean.TRUE;
    }
    return Boolean.FALSE;
  }
  private boolean checkLatestMobileDevice(LatestMobileDevice mobileDevice) {
    if (Objects.isNull(mobileDevice)) {
      return true;
    }
    Long imeiCount = latestMobileDeviceService.getCountByImei(mobileDevice.getImei(),mobileDevice.getSysOrigin());
    if (imeiCount > 1) {
      return true;
    }
    return latestMobileDeviceService.getCountByIp(mobileDevice.getIp(),mobileDevice.getSysOrigin()) > 1;
  }

  public void updateViolationOrNotStatus(Long toUserId){
    inviteRedPacketRecordService.updateViolationOrNotStatus(toUserId,Boolean.FALSE);

  }
  /**
   * 新用户下次可助力时间.
   */
  public Timestamp getNextHelpTime(Long userId) {

    UserProfile userProfile = userProfileGateway.getByUserId(userId);
    if (Objects.isNull(userProfile)||Objects.isNull(userProfile.getCreateTime())) {
      return null;
    }

    Timestamp userRegisterTime = userProfile.getCreateTime();
    LatestMobileDevice mobileDevice = latestMobileDeviceService.getByUserId(userId);
    if (Objects.isNull(mobileDevice)) {
      return null;
    }
    Long imeiCount = latestMobileDeviceService.getCountByImei(mobileDevice.getImei(),mobileDevice.getSysOrigin());
    if (imeiCount > 1) {
      return null;
    }
    Long ipCount = latestMobileDeviceService.getCountByIp(mobileDevice.getIp(),mobileDevice.getSysOrigin());
    if (ipCount > 1) {
      return null;
    }

    InviteUserRedPacketConfigCache redPacketConfig = getInviteConfig(mobileDevice.getSysOrigin());
    if (Objects.isNull(redPacketConfig)) {
      return null;
    }

    // 新用户助力点
    List<Long> days = getNewUserHelpDays(redPacketConfig);
    if (CollectionUtils.isEmpty(days)) {
      return null;
    }
    for (int index = 0; index < days.size(); index++) {

      // 可助力的时间
      long startTime = TimestampUtils.dateTimePlusDays(userRegisterTime, days.get(index) - 1)
              .getTime();
      Timestamp endTime = TimestampUtils.dateTimePlusDays(userRegisterTime, days.get(index));
      // 当前时间
      long nowTime = TimestampUtils.now().getTime();
      if (nowTime >= startTime && nowTime <= endTime.getTime()) {

        // 返回本次可助力截止时间(秒)
        if (CollectionUtils.isEmpty(redPacketInviteUserCacheService.getTodayHelpUsers(userId,
                days.get(index))) || index >= days.size() - 1) {
          return null;
        }
        return TimestampUtils.dateTimePlusDays(userRegisterTime, days.get(index + 1) - 1);
      }
    }
    return null;

  }

  /**
   * 助力.
   */
  private Boolean help(Long userId, Long toUserId, Long day) {
    // 进行助力次数增加
    List<Long> helpUserIds = redPacketInviteUserCacheService.getTodayHelpUsers(userId, day);
    if (CollectionUtils.isNotEmpty(helpUserIds)) {
      // 对应时间已经助力过,不能再次助力
      return Boolean.FALSE;
    }
    // 助力一次
    redPacketInviteUserCacheService.cacheTodayHelpUsers(userId, day, toUserId);
    return Boolean.TRUE;
  }

  /**
   * 新用户助力点.
   */
  private static List<Long> getNewUserHelpDays(InviteUserRedPacketConfigCache redPacketConfig) {
    if (StringUtils.isBlank(redPacketConfig.getNewUserHelpDays())) {
      return Lists.newArrayList();
    }
    return Arrays.stream(redPacketConfig.getNewUserHelpDays().split(",")).map(day -> {
      if (StringUtils.isBlank(day)) {
        return null;
      }
      return Long.parseLong(day.trim());
    }).filter(Objects::nonNull).sorted().collect(Collectors.toList());
  }

}
