package ru.yandex.webmaster3.storage.abt;

import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.storage.abt.dao.AbtExperimentYDao;
import ru.yandex.webmaster3.storage.abt.model.IExperiment;
import ru.yandex.webmaster3.storage.abt.model.UnknownExperiment;

/**
 * ishalaru
 * 12.11.2019
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ExperimentMapperService {
    private static final long CACHE_DURATION_MINUTES = 20;
    private static final UnknownExperiment UNKNOWN_EXPERIMENT = new UnknownExperiment();

    private final AbtExperimentYDao abtExperimentYDao;
    private final LoadingCache<String, Optional<IExperiment>> experimentsCache = CacheBuilder.newBuilder()
            .maximumSize(10_000)
            .refreshAfterWrite(CACHE_DURATION_MINUTES, TimeUnit.MINUTES)
            .build(new CacheLoader<>() {
                @Override
                public Optional<IExperiment> load(@NotNull String experimentName) {
                    return Optional.ofNullable(abtExperimentYDao.select(experimentName));
                }
            });

    public void cleanExperimentsCache() {
        experimentsCache.invalidateAll();
    }

    public IExperiment getExperiment(String name) {
        try {
            return experimentsCache.get(name).orElse(UNKNOWN_EXPERIMENT);
        } catch (ExecutionException e) {
            throw new WebmasterException("Unable to get experiments",
                    new WebmasterErrorResponse.InternalUnknownErrorResponse(this.getClass(), "Unable to get experiments"), e);
        }
    }

    public boolean experimentIsActual(String name) {
        final IExperiment experiment = getExperiment(name);
        return experiment != null && experiment.isActive();
    }

}
