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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.base.Objects;
import org.jetbrains.annotations.TestOnly;

import ru.yandex.qe.dispenser.domain.base_resources.BaseResource;

@TestOnly
public class BaseResourceDaoImpl implements BaseResourceDao {

    private final List<BaseResource> collection = new ArrayList<>();

    @Override
    public synchronized BaseResource create(BaseResource.Builder builder) {
        long nextId = collection.stream().max(Comparator.comparing(BaseResource::getId))
                .map(BaseResource::getId).orElse(-1L) + 1L;
        BaseResource result = builder.build(nextId);
        if (collection.stream().anyMatch(t -> t.getKey().equals(result.getKey())
                || (t.getBaseResourceTypeId() == result.getBaseResourceTypeId()
                        && t.getSegmentIds().equals(result.getSegmentIds())))) {
            throw new IllegalArgumentException("Conflicting base resource already exists");
        }
        collection.add(result);
        return result;
    }

    @Override
    public synchronized Optional<BaseResource> getById(long id) {
        return collection.stream().filter(v -> v.getId() == id).findFirst();
    }

    @Override
    public synchronized Set<BaseResource> getByIds(Collection<? extends Long> ids) {
        if (ids.isEmpty()) {
            return Set.of();
        }
        return collection.stream().filter(v -> ids.contains(v.getId())).collect(Collectors.toSet());
    }

    @Override
    public synchronized List<BaseResource> getPage(Long idFrom, int size) {
        return Optional.ofNullable(idFrom).map(from -> collection.stream()
                        .sorted(Comparator.comparing(BaseResource::getId))
                        .filter(v -> v.getId() > from).limit(size).collect(Collectors.toList()))
                .orElseGet(() -> collection.stream().sorted(Comparator.comparing(BaseResource::getId))
                        .limit(size).collect(Collectors.toList()));
    }

    @Override
    public synchronized Set<BaseResource> getByBaseResourceTypeIds(Collection<? extends Long> ids) {
        if (ids.isEmpty()) {
            return Set.of();
        }
        return collection.stream().filter(v -> ids.contains(v.getBaseResourceTypeId())).collect(Collectors.toSet());
    }

    @Override
    public synchronized Optional<BaseResource> getByKey(String key) {
        return collection.stream().filter(v -> Objects.equal(v.getKey(), key)).findFirst();
    }

    @Override
    public synchronized Set<BaseResource> getByKeys(Collection<? extends String> keys) {
        if (keys.isEmpty()) {
            return Set.of();
        }
        return collection.stream().filter(v -> keys.contains(v.getKey())).collect(Collectors.toSet());
    }

    @Override
    public synchronized void clear() {
        collection.clear();
    }

}
