package com.red.circle.other.infra.database.cache.service.other.impl;

import com.google.common.collect.Lists;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.other.infra.database.cache.entity.game.burstcrystal.GameBurstCrystalProgressCache;
import com.red.circle.other.infra.database.cache.key.GameBurstCrystalKeys;
import com.red.circle.other.infra.database.cache.service.other.GameBurstCrystalThatDayCacheService;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import com.red.circle.tool.core.parse.DataTypeUtils;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * 爆水晶游戏当天 缓存服务 实现.
 *
 * @author pengliang on 2021/7/2
 */
@Service
@RequiredArgsConstructor
public class GameBurstCrystalThatDayCacheServiceImpl implements
    GameBurstCrystalThatDayCacheService {

  private final RedisService redisService;

  @Override
  public GameBurstCrystalProgressCache getCurrentProcessing(Long roomId,
      Function<Long, GameBurstCrystalProgressCache> orElse) {
    return Optional.ofNullable(redisService
            .getStringToObject(getCurrentProcessingKey(roomId),
                GameBurstCrystalProgressCache.class))
        .orElseGet(() -> {
          GameBurstCrystalProgressCache progressCache = orElse.apply(roomId);
          if (Objects.nonNull(progressCache)) {
            redisService.setString(getCurrentProcessingKey(roomId),
                progressCache, 1, TimeUnit.DAYS);
          }
          return progressCache;
        });
  }

  @Override
  public void removeCurrentProcessing(Long roomId) {
    redisService.delete(getCurrentProcessingKey(roomId));
  }

  private String getCurrentProcessingKey(Long roomId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL
        .getKey(roomId, Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }

  @Override
  public Long incrProgressRate(Long progressId, Long quantity) {
    return redisService.increment(getInrKey(progressId), quantity);
  }

  @Override
  public boolean isPreheat(Long progressId) {
    return redisService.setIfAbsent(getPreheatKey(progressId), 1, 1, TimeUnit.DAYS);
  }

  @Override
  public boolean isDraw(Long progressId) {
    return redisService.setIfAbsent(getDrawKey(progressId), 1, 1, TimeUnit.DAYS);
  }

  @Override
  public void removeDraw(Long progressId) {
    redisService.delete(getDrawKey(progressId));
  }

  @Override
  public boolean isInit(Long roomId) {
    return redisService.setIfAbsent(getInitKey(roomId), 1, 1, TimeUnit.DAYS);
  }

  @Override
  public void incrementContribute(Long progressId, Long userId, double quantity) {
    String key = getContributeKey(progressId);
    redisService.zsetIncrementScore(key, String.valueOf(userId), quantity);
    redisService.expire(key, 1, TimeUnit.DAYS);
  }

  @Override
  public List<Long> popContributeTop5(Long progressId) {

    return Optional.ofNullable(
            redisService.zsetGetReverseRange(getContributeKey(progressId), 0, 4))
        .map(v -> v.stream().filter(Objects::nonNull).map(DataTypeUtils::toLong)
            .collect(Collectors.toList()))
        .orElse(Lists.newArrayList());
  }

  @Override
  public List<Long> popContributeTop3(Long progressId) {

    return Optional.ofNullable(
            redisService.zsetGetReverseRange(getContributeKey(progressId), 0, 2))
        .map(v -> v.stream().filter(Objects::nonNull).map(DataTypeUtils::toLong)
            .collect(Collectors.toList()))
        .orElse(Lists.newArrayList());
  }

  @Override
  public void removeContribute(Long progressId) {
    redisService.zsetRemove(getContributeKey(progressId));
  }

  private String getContributeKey(Long progressId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL_CONTRIBUTE
        .getKey(progressId,
            Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }

  private String getInitKey(Long roomId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL_INIT
        .getKey(roomId,
            Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }

  private String getDrawKey(Long progressId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL_DRAW
        .getKey(progressId,
            Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }

  private String getPreheatKey(Long progressId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL_PREHEAT
        .getKey(progressId,
            Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }

  private String getInrKey(Long progressId) {
    return GameBurstCrystalKeys.GAME_BURST_CRYSTAL_INCR
        .getKey(progressId,
            Long.valueOf(ZonedDateTimeAsiaRiyadhUtils.nowDateToInt()));
  }


}
