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

import com.fasterxml.jackson.core.type.TypeReference;
import com.red.circle.common.business.core.EnumConfigCache;
import com.red.circle.common.business.core.enums.EnumConfigHash;
import com.red.circle.other.infra.database.rds.enums.CacheKeysEnum;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.other.infra.convertor.sys.EnumConfigInfraConvertor;
import com.red.circle.other.infra.database.cache.key.EnumConfigHashKeys;
import com.red.circle.other.infra.database.cache.key.EnumConfigKeys;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.rds.service.sys.EnumConfigService;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.inner.model.dto.sys.EnumConfigDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.func.VoidCallable;
import com.red.circle.tool.core.parse.DataTypeUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;

/**
 * @author pengliang on 2020/10/9
 */
@Service
@RequiredArgsConstructor
public class EnumConfigCacheServiceImpl implements EnumConfigCacheService {

  private static final int ENUM_MINUTES = 10;
  private final RedisService redisService;
  private final EnumConfigService enumConfigService;
  private final EnumConfigInfraConvertor enumConfigInfraConvertor;


  @Override
  public List<EnumConfigDTO> listAppConfig(String sysOrigin) {
    return listAppEnumConfigCache(() ->
        enumConfigInfraConvertor.toListEnumConfigDTO(
            enumConfigService.listReturnAppConfig(sysOrigin)), sysOrigin);
  }

  @Override
  public EnumConfigDTO getByCode(EnumConfigKey key, String sysOrigin) {
    return getValue(key.name(), () ->
        enumConfigInfraConvertor.toEnumConfigDTO(
            enumConfigService.getByEnumConfig(key, sysOrigin)), sysOrigin);
  }

  @Override
  public EnumConfigDTO getByCode(String key, String sysOrigin) {
    return getValue(key, () ->
        enumConfigInfraConvertor.toEnumConfigDTO(
            enumConfigService.getByEnumConfig(key, sysOrigin)), sysOrigin);
  }

  @Override
  public String getValue(EnumConfigKey key, String sysOrigin) {
    return Optional.ofNullable(getByCode(key, sysOrigin))
        .map(EnumConfigDTO::getVal)
        .orElse(null);
  }

  @Override
  public Integer getValueInt(EnumConfigKey key, String sysOrigin) {
    return DataTypeUtils.toInteger(getValue(key, sysOrigin));
  }

  @Override
  public Long getValLong(EnumConfigKey key, String sysOrigin) {
    return DataTypeUtils.toLong(getValue(key, sysOrigin));
  }

  @Override
  public BigDecimal getValueBigDecimal(EnumConfigKey key, String sysOrigin) {
    return DataTypeUtils.toBigDecimal(getValue(key, sysOrigin));
  }

  @Override
  public Boolean getValueBool(EnumConfigKey key, String sysOrigin) {
    return DataTypeUtils.toBoolean(getValue(key, sysOrigin));
  }

  @Override
  public BigDecimal giftGoldRatioFormula(BigDecimal ratio, BigDecimal gold) {
    return gold.multiply(ratio).setScale(0, RoundingMode.DOWN);
  }

  @Override
  public BigDecimal getGiftGoldRatio(SysOriginPlatformEnum sysOrigin) {
    return getValueBigDecimal(EnumConfigKey.ASWAT_GIFT_GOLD_RATIO, sysOrigin.name());
  }

  @Override
  public BigDecimal getLuckyGiftGoldRatio(SysOriginPlatformEnum sysOrigin) {
    return getValueBigDecimal(EnumConfigKey.ASWAT_LUCKY_GIFT_GOLD_RATIO, sysOrigin.name());
  }

  @Override
  public BigDecimal getGiftGoldRatioSelf(SysOriginPlatformEnum sysOrigin) {
    return getValueBigDecimal(EnumConfigKey.ASWAT_GIFT_GOLD_RATIO_SELF, sysOrigin.name());
  }

  @Override
  public BigDecimal toDiamondQuantity(EnumConfigKey key, String sysOrigin) {
    return goldsToDiamondQuantity(getValueBigDecimal(key, sysOrigin), sysOrigin);
  }

  @Override
  public BigDecimal goldsToDiamondQuantity(BigDecimal gold, String sysOrigin) {
    return goldsToDiamondQuantity(gold, getDiamondEqGold(sysOrigin));
  }

  @Override
  public BigDecimal goldsToDiamondQuantity(BigDecimal gold, BigDecimal exchangeRatio) {
    return gold.multiply(exchangeRatio).setScale(0, RoundingMode.DOWN);
  }

  @Override
  public BigDecimal getDiamondEqGold(String sysOrigin) {
//    BigDecimal quantity = getValueBigDecimal(EnumConfigKey.DIAMOND_EQ_GOLD, sysOrigin);
//    ResponseAssert.isTrue(CommonErrorCode.NOT_FOUND_ENUM_SETTING, ArithmeticUtils.gtZero(quantity));
//    return quantity;
    return BigDecimal.ZERO;
  }

  @Override
  public BigDecimal getDiamondExchangeMultiple(String sysOrigin) {
//    BigDecimal multiple = getValueBigDecimal(EnumConfigKey.DIAMOND_EXCHANGE_MULTIPLE, sysOrigin);
//    ResponseAssert.isTrue(CommonErrorCode.NOT_FOUND_ENUM_SETTING, ArithmeticUtils.gtZero(multiple));
//    return multiple;
    return BigDecimal.ZERO;
  }

  @Override
  public BigDecimal getDiamondExchangeMaxGold(String sysOrigin) {
//    BigDecimal maxGold = getValueBigDecimal(EnumConfigKey.DIAMOND_EXCHANGE_MAX_GOLD, sysOrigin);
//    ResponseAssert.isTrue(CommonErrorCode.NOT_FOUND_ENUM_SETTING, ArithmeticUtils.gtZero(maxGold));
//    return maxGold;
    return BigDecimal.ZERO;
  }


  private List<EnumConfigDTO> listAppEnumConfigCache(VoidCallable<List<EnumConfigDTO>> elseGet,
      String sysOrigin) {

    List<EnumConfigDTO> enumConfigs = redisService.hashGet(
        getEnumHashKey(sysOrigin),
        EnumConfigHashKeys.LIST.name(),
        new TypeReference<>() {
        });

    if (CollectionUtils.isNotEmpty(enumConfigs)) {
      return enumConfigs;
    }

    if (Objects.isNull(elseGet)) {
      return enumConfigs;
    }

    List<EnumConfigDTO> newEnumConfigs = elseGet.apply();

    if (CollectionUtils.isNotEmpty(newEnumConfigs)) {
      redisService.hashPut(getEnumHashKey(sysOrigin),
          EnumConfigHashKeys.LIST.name(),
          newEnumConfigs,
          ENUM_MINUTES,
          TimeUnit.MINUTES);
    }

    return newEnumConfigs;
  }

  private EnumConfigDTO getValue(String key, VoidCallable<EnumConfigDTO> voidCallable,
      String sysOrigin) {
    EnumConfigDTO enumConfig = redisService.hashGet(getEnumHashKey(sysOrigin), key,
        EnumConfigDTO.class);
    return Optional.ofNullable(enumConfig).orElseGet(() -> {
      EnumConfigDTO newVal = voidCallable.apply();
      putValue(key, newVal, sysOrigin);
      return newVal;
    });
  }

  @Override
  public void putValue(String key, EnumConfigDTO value, String sysOrigin) {
    redisService.hashPut(getEnumHashKey(sysOrigin), key, value);
  }

  @Override
  public void remove(String key, String sysOrigin) {
    redisService.hashDelete(getEnumHashKey(sysOrigin), key);
  }

  @Override
  public void removeAll(String sysOrigin) {
    redisService.delete(getEnumHashKey(sysOrigin));
  }

  private String getEnumHashKey(String sysOrigin) {
    return EnumConfigKeys.HASH.getKey(sysOrigin);
  }

//  @Override
//  public List<EnumConfigCache> listAppEnumConfigCache(VoidCallable<List<EnumConfigCache>> elseGet,
//      String sysOrigin) {
//
//    List<EnumConfigCache> enumConfigCaches = hashListOperations
//        .get(getRootEnumConfigKey(sysOrigin), EnumConfigHash.APP_LIST.name());
//
//    if (CollectionUtils.isNotEmpty(enumConfigCaches)) {
//      return enumConfigCaches;
//    }
//
//    if (Objects.isNull(elseGet)) {
//      return enumConfigCaches;
//    }
//
//    enumConfigCaches = elseGet.apply();
//
//    if (CollectionUtils.isEmpty(enumConfigCaches)) {
//      return enumConfigCaches;
//    }
//
//    hashListOperations
//        .put(getRootEnumConfigKey(sysOrigin), EnumConfigHash.APP_LIST.name(), enumConfigCaches);
//    return enumConfigCaches;
//  }



//  @Override
//  public EnumConfigCache getValue(String key, VoidCallable<EnumConfigCache> voidCallable,
//      String sysOrigin) {
//    EnumConfigCache enumConfigCache = hashOperations.get(getRootEnumConfigKey(sysOrigin), key);
//    return Optional.ofNullable(enumConfigCache).orElseGet(() -> {
//      EnumConfigCache newVal = voidCallable.apply();
//      cacheValue(key, newVal, sysOrigin);
//      return newVal;
//    });
//  }

  private String getRootEnumConfigKey(String sysOrigin) {
    return CacheKeysEnum.ENUM_CONFIG.getAppendKey(sysOrigin);
  }

}
