package ru.yandex.webmaster3.storage.indexing2.samples;

import java.util.Comparator;
import java.util.List;
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.joda.time.Instant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.searchquery.OrderDirection;
import ru.yandex.webmaster3.storage.indexing2.internal.dao.IndexingSamplesTablesYDao;
import ru.yandex.webmaster3.storage.indexing2.internal.data.IndexingSamplesImportType;
import ru.yandex.webmaster3.storage.indexing2.internal.data.IndexingSamplesTableInfo;
import ru.yandex.webmaster3.storage.indexing2.internal.data.IndexingSamplesTableState;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexedUrlSampleCHDao;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexedUrlSamplesOrderField;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexingEventSamplesCHDao;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexingEventsOrderField;
import ru.yandex.webmaster3.storage.indexing2.samples.data.IndexedUrlEventSample;
import ru.yandex.webmaster3.storage.indexing2.samples.data.IndexedUrlSample;
import ru.yandex.webmaster3.storage.indexing2.samples.data.IndexingEventsAvailableCodes;
import ru.yandex.webmaster3.storage.util.clickhouse2.condition.Condition;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.OrderBy;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

/**
 * @author avhaliullin
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class IndexingSamplesService {
    private static final long CACHE_DURATION_MINUTES = 1L;

    private final LoadingCache<IndexingSamplesImportType, String> DATA_VERSION_CACHE = CacheBuilder.newBuilder()
            .maximumSize(10)
            .expireAfterAccess(CACHE_DURATION_MINUTES, TimeUnit.MINUTES)
            .build(new CacheLoader<>() {
                public String load(IndexingSamplesImportType type) {
                    return getDataVersion(type);
                }
            });

    private final IndexingEventSamplesCHDao mdbIndexingEventSamplesCHDao;
    private final IndexedUrlSampleCHDao mdbIndexedUrlSampleCHDao;
    private final IndexingSamplesTablesYDao indexingSamplesTablesYDao;

    public IndexingEventsAvailableCodes getIndexingEventAvailableCodes(WebmasterHostId hostId, Condition filters) {
        return mdbIndexingEventSamplesCHDao.getDistinctCodes(hostId, filters);
    }

    public List<YandexHttpStatus> getIndexedSampleAvailableCodes(WebmasterHostId hostId, Condition filters) {
        return mdbIndexedUrlSampleCHDao.getDistinctCodes(hostId, filters);
    }

    public long getEventSamplesCount(WebmasterHostId hostId, Condition filters) {
        return mdbIndexingEventSamplesCHDao.getSamplesCount(hostId, filters);
    }

    public long getSamplesCount(WebmasterHostId hostId, Condition filters) {
        return mdbIndexedUrlSampleCHDao.getSamplesCount(hostId, filters);
    }

    public List<IndexedUrlEventSample> getEventSamples(WebmasterHostId hostId, Condition filters,
                                                       IndexingEventsOrderField orderBy, OrderDirection orderDirection,
													   int limitFrom, int limitSize) {
        OrderBy.Direction direction = orderDirection == OrderDirection.ASC ? OrderBy.Direction.ASC : OrderBy.Direction.DESC;
        return mdbIndexingEventSamplesCHDao.getSamples(hostId, filters, orderBy, direction, limitFrom, limitSize);
    }

    public List<IndexedUrlSample> getSamples(WebmasterHostId hostId, Condition filters,
                                             IndexedUrlSamplesOrderField orderBy, OrderDirection orderDirection,
                                             int limitFrom, int limitSize) {
        OrderBy.Direction direction = orderDirection == OrderDirection.ASC ? OrderBy.Direction.ASC : OrderBy.Direction.DESC;
        return mdbIndexedUrlSampleCHDao.getSamples(hostId, filters, orderBy, direction, limitFrom, limitSize);
    }

    public List<IndexedUrlSample> getSamples(WebmasterHostId hostId, String path) {
        return mdbIndexedUrlSampleCHDao.getSamples(hostId, path);
    }

    public String getEventSamplesDataVersion(WebmasterHostId hostId) {
        return DATA_VERSION_CACHE.getUnchecked(IndexingSamplesImportType.EVENT_SAMPLES);
    }

    public String getUrlSamplesDataVersion(WebmasterHostId hostId) {
        return DATA_VERSION_CACHE.getUnchecked(IndexingSamplesImportType.URL_SAMPLES);
    }

    private String getDataVersion(IndexingSamplesImportType importType) {
        return indexingSamplesTablesYDao.listAllTables()
                .stream()
                .filter(t -> !t.isTail() && t.getState() == IndexingSamplesTableState.DONE && t.getImportType() ==importType)
                .map(IndexingSamplesTableInfo::getUpdateTime)
                .sorted(Comparator.reverseOrder())
                .findFirst()
                .map(Instant::toString)
                .orElse("unknown");
    }

}
