package com.atlassian.bitbucket.mesh.git.cache;

import com.atlassian.bitbucket.mesh.config.PackCacheConfig;
import com.atlassian.util.contentcache.CacheEntry;
import com.atlassian.util.contentcache.ContentCache;
import com.atlassian.util.contentcache.TtlCacheExpiryStrategy;
import com.google.common.collect.Sets;

import javax.annotation.Nonnull;
import java.util.*;

import static java.util.Objects.requireNonNull;

public class PackCacheExpiryStrategy extends TtlCacheExpiryStrategy {

    // least recently accessed first
    private static final Comparator<CacheEntry> ENTRY_COMPARATOR =
            Comparator.<CacheEntry, Date>comparing(cacheEntry -> cacheEntry.getStatistics().getLastAccessedDate())
                    .thenComparing(cacheEntry -> cacheEntry.getStatistics().getKey());

    private final PackCacheConfig packCacheConfig;

    public PackCacheExpiryStrategy(@Nonnull PackCacheConfig packCacheConfig) {
        this.packCacheConfig = requireNonNull(packCacheConfig, "packCacheConfig");
    }

    @Nonnull
    @Override
    public Iterable<CacheEntry> getExpiredEntries(@Nonnull ContentCache cache) {
        TreeSet<CacheEntry> entries = new TreeSet<>(ENTRY_COMPARATOR);
        Set<CacheEntry> expired = Sets.newHashSet();

        for (Map.Entry<String, CacheEntry> entry : cache.getEntries().entrySet()) {
            if (isExpired(entry.getValue())) {
                expired.add(entry.getValue());
                continue;
            }

            entries.add(entry.getValue());
        }

        int toBeRemoved = entries.size() - packCacheConfig.getMaxCount();
        Iterator<CacheEntry> it = entries.iterator();
        while (toBeRemoved-- > 0) {
            expired.add(it.next());
        }

        return expired;
    }
}
