package com.red.circle.other.app.common.gift;

import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.live.LiveHeartbeatCache;
import com.red.circle.other.infra.database.cache.service.other.LiveHeartbeatCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile;
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
import com.red.circle.other.infra.database.mongo.service.live.RoomContributionCountService;
import com.red.circle.other.infra.database.mongo.service.live.RoomContributionRankCountService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.service.live.RoomContributionBalanceService;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class LuckyGiftRewardSettlementService {

  private static final BigDecimal REWARD_RATIO = new BigDecimal("0.1");

  private final UserRegionGateway userRegionGateway;
  private final LiveHeartbeatCacheService liveHeartbeatCacheService;
  private final RoomProfileManagerService roomProfileManagerService;
  private final RoomContributionRankCountService roomContributionRankCountService;
  private final RoomContributionBalanceService roomContributionBalanceService;
  private final RoomContributionCountService roomContributionCountService;
  private final RoomContributionActivityCountService roomContributionActivityCountService;

  public void settle(LuckyGiftRewardStreamEvent event) {
    if (event == null || event.getRoomId() == null || event.getSendUserId() == null
        || CollectionUtils.isEmpty(event.getResults())) {
      return;
    }

    applyHeartbeat(event);
    applyRoomContribution(event);
  }

  private void applyHeartbeat(LuckyGiftRewardStreamEvent event) {
    Map<Long, Long> increments = new HashMap<>();
    for (LuckyGiftRewardStreamEvent.Result result : event.getResults()) {
      if (result == null || result.getAcceptUserId() == null || result.getRewardNum() == null
          || result.getRewardNum() <= 0) {
        continue;
      }
      long increment = calcRewardIncrement(result.getRewardNum());
      if (increment <= 0) {
        continue;
      }
      increments.merge(result.getAcceptUserId(), increment, Long::sum);
    }

    if (increments.isEmpty()) {
      return;
    }

    List<LiveHeartbeatCache> liveHeartbeatCaches = liveHeartbeatCacheService.listLiveHeartbeat(
        event.getRoomId());
    Map<Long, LiveHeartbeatCache> heartbeatMap = mapHeartbeatCaches(liveHeartbeatCaches);
    increments.forEach((userId, increment) -> heartbeatMap.compute(userId, (key, current) -> {
      LiveHeartbeatCache target = current == null
          ? new LiveHeartbeatCache().setId(userId).setHeartbeatVal(0L)
          : current;
      long total = Objects.requireNonNullElse(target.getHeartbeatVal(), 0L) + increment;
      target.setHeartbeatVal(total);
      return target;
    }));

    liveHeartbeatCacheService.create(event.getRoomId(), new ArrayList<>(heartbeatMap.values()));
  }

  private void applyRoomContribution(LuckyGiftRewardStreamEvent event) {
    RoomProfile roomProfile = roomProfileManagerService.getProfileById(event.getRoomId());
    if (roomProfile == null) {
      log.warn("skip lucky gift room contribution because room profile missing. eventId={} roomId={}",
          event.getEventId(), event.getRoomId());
      return;
    }

    String roomCode = userRegionGateway.getRegionCode(roomProfile.getUserId());
    String sendUserCode = userRegionGateway.getRegionCode(event.getSendUserId());
    if (!Objects.equals(roomCode, sendUserCode)) {
      return;
    }

    long totalReward = event.getResults().stream()
        .filter(Objects::nonNull)
        .map(LuckyGiftRewardStreamEvent.Result::getRewardNum)
        .filter(Objects::nonNull)
        .filter(rewardNum -> rewardNum > 0)
        .mapToLong(Long::longValue)
        .sum();
    long contributionQuantity = calcRewardIncrement(totalReward);
    if (contributionQuantity <= 0) {
      return;
    }

    BigDecimal quantity = BigDecimal.valueOf(contributionQuantity);
    roomContributionRankCountService.incr(roomProfile.getSysOrigin(), roomProfile.getId(),
        event.getSendUserId(), quantity);
    roomContributionBalanceService.incrTotalQuantity(roomProfile.getId(), roomProfile.getUserId(),
        quantity);
    roomContributionCountService.incrQuantity(roomProfile.getSysOrigin(), roomProfile.getId(),
        roomProfile.getUserId(), quantity);
    roomContributionActivityCountService.incrQuantity(roomProfile.getId(), quantity);
  }

  private long calcRewardIncrement(Long rewardNum) {
    if (rewardNum == null || rewardNum <= 0) {
      return 0L;
    }
    return BigDecimal.valueOf(rewardNum)
        .multiply(REWARD_RATIO)
        .setScale(0, RoundingMode.DOWN)
        .longValue();
  }

  private Map<Long, LiveHeartbeatCache> mapHeartbeatCaches(List<LiveHeartbeatCache> list) {
    if (CollectionUtils.isEmpty(list)) {
      return new HashMap<>();
    }
    Map<Long, LiveHeartbeatCache> result = new HashMap<>(list.size());
    for (LiveHeartbeatCache cache : list) {
      if (cache != null && cache.getId() != null) {
        result.put(cache.getId(), cache);
      }
    }
    return result;
  }
}
