package ru.yandex.qe.dispenser.domain.dao.resources_model;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.springframework.stereotype.Component;

import ru.yandex.qe.dispenser.domain.resources_model.DeliverableResource;
import ru.yandex.qe.dispenser.domain.resources_model.ResourcesModelMapping;

@Component
public class ResourcesModelMappingCache {

    private final LoadingCache<Long, Map<DeliverableResource, List<ResourcesModelMapping>>> cache;

    public ResourcesModelMappingCache(ResourcesModelMappingDao resourcesModelMappingDao) {
        this.cache = CacheBuilder.newBuilder()
                .expireAfterWrite(5, TimeUnit.MINUTES)
                .maximumSize(100)
                .build(new Loader(resourcesModelMappingDao));
    }

    public Map<DeliverableResource, List<ResourcesModelMapping>> getByCampaignId(long campaignId) {
        try {
            return cache.get(campaignId);
        } catch (ExecutionException e) {
            throw new UncheckedExecutionException(e);
        }
    }

    private static final class Loader extends CacheLoader<Long, Map<DeliverableResource, List<ResourcesModelMapping>>> {

        private final ResourcesModelMappingDao resourcesModelMappingDao;

        private Loader(ResourcesModelMappingDao resourcesModelMappingDao) {
            this.resourcesModelMappingDao = resourcesModelMappingDao;
        }

        @Override
        public Map<DeliverableResource, List<ResourcesModelMapping>> load(Long key) {
            return resourcesModelMappingDao.getResourcesMappingsForCampaign(key).stream().collect(Collectors
                    .groupingBy(m -> new DeliverableResource(m.getResource(), m.getSegments()), Collectors.toList()));
        }

        @Override
        public Map<Long, Map<DeliverableResource, List<ResourcesModelMapping>>> loadAll(Iterable<? extends Long> keys) {
            return resourcesModelMappingDao.getResourcesMappingsForCampaigns(Sets.newHashSet(keys)).stream()
                    .collect(Collectors.groupingBy(ResourcesModelMapping::getCampaignId,
                            Collectors.groupingBy(m -> new DeliverableResource(m.getResource(), m.getSegments()),
                                    Collectors.toList())));
        }

    }

}
