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

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

import org.jetbrains.annotations.NotNull;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;

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

public interface InMemoryKeyDao<T extends Keyable<K>, K extends Comparable<K>, PK extends Serializable> extends InMemoryDao<T, PK>, KeyDao<T, K, PK> {
    @NotNull
    @Override
    default T read(@NotNull final K key) throws EmptyResultDataAccessException {
        return filter(obj -> obj.getKey().equals(key))
                .findAny()
                .orElseThrow(() -> new EmptyResultDataAccessException("No object in " + getClass().getSimpleName() + " with key '" + key + "'!", 1));
    }

    @NotNull
    @Override
    default Map<K, T> readAll(@NotNull final Collection<K> keys) {
        if (keys.isEmpty()) {
            return Collections.emptyMap();
        }
        final Map<K, T> result = StreamUtils.keyIndex(filter(obj -> keys.contains(obj.getKey())));
        for (final K key : keys) {
            if (!result.containsKey(key)) {
                throw new IncorrectResultSizeDataAccessException("No object in " + getClass().getSimpleName() + " with key '" + key + "'!", keys.size(), result.size());
            }
        }
        return result;
    }

    interface Normalized<T extends Keyable<K>, K extends Comparable<K>> extends InMemoryKeyDao<T, K, Long> {
    }
}
