package org.atlasapi.query.v5.search;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.atlasapi.content.Content;
import org.atlasapi.entity.Id;
import org.atlasapi.equivalence.MergingEquivalentsResolver;
import org.atlasapi.equivalence.ResolvedEquivalents;
import org.atlasapi.query.common.QueryResult;
import org.atlasapi.query.common.context.QueryContext;

import com.metabroadcast.common.ids.NumberToShortStringCodec;
import com.metabroadcast.sherlock.client.search.ContentSearcher;
import com.metabroadcast.sherlock.client.search.SearchQuery;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import static com.google.common.base.Preconditions.checkNotNull;

public class ContentResolvingSearcher {

    private final ContentSearcher searcher;
    private final MergingEquivalentsResolver<Content> contentResolver;
    private final long timeout;

    public ContentResolvingSearcher(
            ContentSearcher searcher,
            MergingEquivalentsResolver<Content> contentResolver,
            long timeout
    ) {
        this.searcher = checkNotNull(searcher);
        this.contentResolver = checkNotNull(contentResolver);
        this.timeout = timeout;
    }

    public QueryResult<Content> search(SearchQuery searchQuery, QueryContext queryContext) {
        try {
            AtomicLong totalResults = new AtomicLong();
            return Futures.transform(
                    Futures.transformAsync(
                            searcher.searchForIds(searchQuery),
                            input -> {
                                totalResults.set(input.getTotalResults());
                                return resolve(input.getIds(), queryContext);
                            }
                    ),
                    (Function<ResolvedEquivalents<Content>, QueryResult<Content>>)
                    resolved -> QueryResult.listResult(
                            resolved.getFirstElems(),
                            queryContext,
                            totalResults.get()
                    )
            ).get(timeout, TimeUnit.MILLISECONDS);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    private ListenableFuture<ResolvedEquivalents<Content>> resolve(
            Iterable<String> encodedIds,
            QueryContext queryContext
    ) {
        List<Id> ids = StreamSupport.stream(encodedIds.spliterator(), false)
                .map(Id::valueOf)
                .collect(Collectors.toList());

        if (ids.isEmpty()) {
            return Futures.immediateFuture(ResolvedEquivalents.empty());
        } else {
            return contentResolver.resolveIds(
                    ids,
                    queryContext.getApplication(),
                    queryContext.getAnnotations().all(),
                    queryContext.getOperands()
            );
        }
    }
}

@@ -179,47 +179,8 @@
 ors;
-%0Aimport java.util.stream.StreamSupport;
 %0A%0Aim
@@ -464,70 +464,8 @@
 t;%0A%0A
-import com.metabroadcast.common.ids.NumberToShortStringCodec;%0A
 impo
@@ -631,100 +631,8 @@
 on;%0A
-import com.google.common.collect.ImmutableList;%0Aimport com.google.common.collect.Iterables;%0A
 impo
@@ -1605,19 +1605,23 @@
 earchFor
-Ids
+Content
 (searchQ
@@ -2422,27 +2422,21 @@
     
-Iterable%3CStri
+List%3CLo
 ng%3E 
+d
 e
-n
 code
@@ -2514,60 +2514,26 @@
 s = 
-StreamSupport.stream(encodedIds.spliterator(), false
+decodedIds.stream(
 )%0A  

Update searching method name and type for Sherlock.