package com.gitee.sop.admin.service.sys;

import com.gitee.fastmybatis.core.support.BaseLambdaService;
import com.gitee.sop.admin.common.config.IConfig;
import com.gitee.sop.admin.common.util.CopyUtil;
import com.gitee.sop.admin.dao.entity.SysConfig;
import com.gitee.sop.admin.dao.mapper.SysConfigMapper;
import com.gitee.sop.admin.service.sys.dto.SystemConfigDTO;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author 六如
 */
@Service
public class SysConfigService extends BaseLambdaService<SysConfig, SysConfigMapper> implements IConfig {

    @Autowired
    private Environment environment;

    // key: configKey, value: configValue
    private final LoadingCache<String, Optional<String>> configCache = CacheBuilder.newBuilder()
            .expireAfterAccess(15, TimeUnit.MINUTES)
            .build(new CacheLoader<String, Optional<String>>() {
                @Override
                public Optional<String> load(String key) throws Exception {
                    return Optional.ofNullable(getConfigValue(key, null));
                }
            });

    public void save(Collection<SystemConfigDTO> configs) {
        configs.forEach(this::setConfig);
    }

    public String getRawValue(String key) {
        return this.query()
                .eq(SysConfig::getConfigKey, key)
                .getValue(SysConfig::getConfigValue);
    }

    public void setConfig(String key, String value) {
        setConfig(key, value, "");
    }

    public void setConfig(String key, String value, String remark) {
        SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
        systemConfigDTO.setConfigKey(key);
        systemConfigDTO.setConfigValue(value);
        systemConfigDTO.setRemark(remark);
        setConfig(systemConfigDTO);
    }

    public void setConfig(SystemConfigDTO systemConfigDTO) {
        Objects.requireNonNull(systemConfigDTO.getConfigKey(), "need key");
        Objects.requireNonNull(systemConfigDTO.getConfigValue(), "need value");
        SysConfig systemConfig = get(SysConfig::getConfigKey, systemConfigDTO.getConfigKey());
        if (systemConfig == null) {
            systemConfig = CopyUtil.copyBean(systemConfigDTO, SysConfig::new);
            this.save(systemConfig);
        } else {
            CopyUtil.copyPropertiesIgnoreNull(systemConfigDTO, systemConfig);
            this.update(systemConfig);
        }
        configCache.invalidate(systemConfigDTO.getConfigKey());
    }

    /**
     * 获取配置信息
     * <pre>
     *  优先级：
     *  数据库
     *  Environment
     *  默认配置
     * </pre>
     *
     * @param key          配置key
     * @param defaultValue 没有获取到返回的默认值
     * @return 返回配置信息，如果没有获取到值，则返回默认值
     */
    public String getConfigValue(String key, String defaultValue) {
        Objects.requireNonNull(key, "need key");
        SysConfig systemConfig = get(SysConfig::getConfigKey, key);
        return Optional.ofNullable(systemConfig)
                .map(SysConfig::getConfigValue)
                .orElseGet(() -> environment.getProperty(key, defaultValue));
    }

    @Override
    public String getConfig(String key) {
        return configCache.getUnchecked(key).orElse(null);
    }

    @Override
    public String getConfig(String key, String defaultValue) {
        return configCache.getUnchecked(key).orElse(defaultValue);
    }

}
