package ru.yandex.webmaster3.storage.cache;

import com.google.common.base.Preconditions;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ArrayUtils;
import org.joda.time.Duration;
import org.joda.time.Instant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.storage.cache.dao.DashboardCacheYDao;

import java.io.IOException;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author aherman
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class DashboardCacheService {
    @Value("${webmaster3.storage.dashboard.cachingEnabled}")
    private boolean cachingEnabled;

    private final DashboardCacheYDao dashboardCacheYDao;

    /**
     * Параметры запроса (кроме id хоста) намеренно не участвуют в ключе кэша - в дашборде пользователь настройками
     * управлять не может, так что параметры могут отличаться только между версиями фронтенда. Это допустимое зло.
     */
    public <T> Optional<T> getData(WebmasterHostId hostId, DashboardType type, String key, Mapper<T> mapper) throws IOException {
        if (!cachingEnabled) {
            return Optional.empty();
        }

        byte[] cacheData = dashboardCacheYDao.getData(hostId, type, key);
        return cacheData == null? Optional.empty() : mapper.apply(cacheData);
    }

    public <T> Optional<T> getDataUnchecked(WebmasterHostId hostId, DashboardType type, String key, Function<byte[], T> mapper) {
        if (!cachingEnabled) {
            return Optional.empty();
        }

        byte[] cacheData = dashboardCacheYDao.getData(hostId, type, key);
        return cacheData == null? Optional.empty() : Optional.of(mapper.apply(cacheData));
    }

    public void saveData(WebmasterHostId hostId, DashboardType type, String key, byte[] data) {
        saveData(hostId, type, key, data, DashboardCacheYDao.TTL);
    }

    public void saveData(WebmasterHostId hostId, DashboardType type, String key, byte[] data, Duration  ttl) {
        // ttl у таблицы в базе равен DashboardCacheYDao.TTL
        Preconditions.checkArgument(!ttl.isLongerThan(DashboardCacheYDao.TTL));

        if (!ArrayUtils.isEmpty(data)) {
            dashboardCacheYDao.saveData(hostId, type, key, data, Instant.now(), ttl);
        }
    }

    public void invalidate(WebmasterHostId hostId, DashboardType type, String key) {
        dashboardCacheYDao.delete(hostId, type, key);
    }

    public interface Mapper<T> {
        Optional<T> apply(byte[] buff) throws IOException;
    }
}
