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

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;

import ru.yandex.qe.dispenser.api.Keyable;
import ru.yandex.qe.dispenser.domain.util.CollectionUtils;
import ru.yandex.qe.dispenser.domain.util.StreamUtils;

public interface KeyDao<T extends Keyable<K>, K extends Comparable<K>, PK extends Serializable> extends GenericDao<T, PK>, ReadOnlyDao<T, K, PK> {
    Logger LOG = LoggerFactory.getLogger(KeyDao.class);

    @NotNull
    default Map<K, T> createAll(@NotNull final Collection<T> objects) {
        return StreamUtils.toMap(objects.stream().map(this::create), Keyable::getKey);
    }

    @NotNull
    default T createIfAbsent(@NotNull final T obj) {
        try {
            return read(obj.getKey());
        } catch (EmptyResultDataAccessException ignored) {
            return create(obj);
        }
    }

    @NotNull
    default Map<K, T> createAllIfAbsent(@NotNull final Collection<T> objects) {
        final Set<K> keys = CollectionUtils.keys(objects);
        LOG.debug("Creating objects if absent: {}", keys);
        final Map<K, T> presentObjects = readPresent(keys);
        final Set<T> absentObjects = CollectionUtils.filter(objects, obj -> !presentObjects.containsKey(obj.getKey()));
        LOG.debug("Creating objects: {}", CollectionUtils.keys(absentObjects));
        final Map<K, T> result = createAll(absentObjects);
        result.putAll(presentObjects);
        return result;
    }
}
