package com.autonomy.abc.query;

import com.autonomy.abc.selenium.error.Errors;
import com.autonomy.abc.selenium.query.QueryResultsPage;
import com.autonomy.abc.selenium.query.QueryService;
import org.hamcrest.Matcher;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import static com.autonomy.abc.framework.ABCAssert.assertThat;
import static com.autonomy.abc.matchers.StringMatchers.containsString;
import static com.autonomy.abc.matchers.StringMatchers.stringContainingAnyOf;

public class QueryTestHelper<T extends QueryResultsPage> {
    private final static List<String> HIDDEN_BOOLEANS = Arrays.asList(
            "NOTed",
            "ANDREW",
            "ORder",
            "WHENCE",
            "SENTENCED",
            "PARAGRAPHING",
            "NEARLY",
            "SENTENCE1D",
            "PARAGRAPHING",
            "PARAGRAPH2inG",
            "SOUNDEXCLUSIVE",
            "XORING",
            "EORE",
            "DNEARLY",
            "WNEARING",
            "YNEARD",
            "AFTERWARDS",
            "BEFOREHAND",
            "NOTWHENERED"
    );

    private final QueryService<T> service;

    public QueryTestHelper(QueryService<T> queryService) {
        service = queryService;
    }

    public void hiddenQueryOperatorText(final Matcher<? super String> errorMatcher) {
        for (Result result : resultsFor(HIDDEN_BOOLEANS)) {
            assertThat("able to search for " + result.term, result.getText(), errorMatcher);

        }
    }

    public void mismatchedBracketQueryText(final Serializable invalidator) {
        List<String> queryTerms = Arrays.asList(
                "(",
                ")",
                "()",
                ") (",
                ")war"
        );

        for (Result result : resultsFor(queryTerms)) {
            assertThat("query term " + result.term + " is invalid",
                    result.getText(), containsString(invalidator));
            assertThat("query term " + result.term + " has sensible error message",
                    result.getText(), stringContainingAnyOf(Arrays.asList(
                            Errors.Search.INVALID,
                            Errors.Search.OPERATORS,
                            Errors.Search.STOPWORDS
                    ))
            );
        }
    }

    public void mismatchedQuoteQueryText(final Serializable invalidator) {
        // TODO: cover "", "\"\"" and " " in whitespace test
        List<String> queryTerms = Arrays.asList(
                "\"",
                "\"word",
                "\" word",
                "\" wo\"rd\""
        );
        for (Result result : resultsFor(queryTerms)) {
            assertThat(result.getText(), containsString(Errors.Search.QUOTES));
            assertThat("query term " + result.term + " has sensible error message", result.getText(), containsString(invalidator));
        }
    }

    private Iterable<Result> resultsFor(final Iterable<String> queries) {
        return new Iterable<Result>() {
            @Override
            public Iterator<Result> iterator() {
                final Iterator<String> queryIterator = queries.iterator();
                return new Iterator<Result>() {
                    @Override
                    public boolean hasNext() {
                        return queryIterator.hasNext();
                    }

                    @Override
                    public Result next() {
                        final String queryTerm = queryIterator.next();
                        T page = service.search(queryTerm);
                        return new Result(queryTerm, page);
                    }
                };
            }
        };
    }
    
    private class Result {
        final String term;
        final T page;
        private String text;

        Result(String term, T page) {
            this.term = term;
            this.page = page;
        }

        String getText() {
            if (text == null) {
                text = page.getText();
            }
            return text;
        }
    }
}

@@ -1126,24 +1126,365 @@
 ERED%22%0A    );
+%0A    private final static List%3CString%3E MISMATCHED_BRACKETS = Arrays.asList(%0A            %22(%22,%0A            %22)%22,%0A            %22()%22,%0A            %22) (%22,%0A            %22)war%22%0A    );%0A    private final static List%3CString%3E MISMATCHED_QUOTES = Arrays.asList(%0A            %22%5C%22%22,%0A            %22%5C%22word%22,%0A            %22%5C%22 word%22,%0A            %22%5C%22 wo%5C%22rd%5C%22%22%0A    );
 %0A%0A    privat
@@ -1953,179 +1953,8 @@
 ) %7B%0A
-        List%3CString%3E queryTerms = Arrays.asList(%0A                %22(%22,%0A                %22)%22,%0A                %22()%22,%0A                %22) (%22,%0A                %22)war%22%0A        );%0A%0A
     
@@ -1985,34 +1985,43 @@
  resultsFor(
-queryTerms
+MISMATCHED_BRACKETS
 )) %7B%0A       
@@ -2659,173 +2659,8 @@
 est%0A
-        List%3CString%3E queryTerms = Arrays.asList(%0A                %22%5C%22%22,%0A                %22%5C%22word%22,%0A                %22%5C%22 word%22,%0A                %22%5C%22 wo%5C%22rd%5C%22%22%0A        );%0A
     
@@ -2699,18 +2699,25 @@
 For(
-queryTerms
+MISMATCHED_QUOTES
 )) %7B
@@ -3511,33 +3511,25 @@
     
-final String queryTerm = 
+return resultFor(
 quer
@@ -3540,24 +3540,25 @@
 rator.next()
+)
 ;%0A          
@@ -3555,32 +3555,138 @@
                 
+    %7D%0A                %7D;%0A            %7D%0A        %7D;%0A    %7D%0A%0A    private Result resultFor(String queryTerm) %7B%0A
         T page =
@@ -3713,32 +3713,16 @@
 yTerm);%0A
-                
         
@@ -3761,74 +3761,8 @@
 e);%0A
-                    %7D%0A                %7D;%0A            %7D%0A        %7D;%0A
     

Move around bits of QueryTestHelper