package uk.ac.ebi.quickgo.annotation.controller;

import uk.ac.ebi.quickgo.annotation.IdGeneratorUtil;
import uk.ac.ebi.quickgo.annotation.service.comm.rest.ontology.model.BasicOntology;
import uk.ac.ebi.quickgo.annotation.service.comm.rest.ontology.model.BasicTaxonomyNode;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.client.ResponseCreator;

import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;

/**
 * @author Tony Wardell
 * Date: 20/12/2017
 * Time: 13:17
 * Created with IntelliJ IDEA.
 */
public class StatsSetupHelper {
    private static final String GO_TERM_RESOURCE_FORMAT = "/ontology/go/terms/%s";
    private static final String ECO_TERM_RESOURCE_FORMAT = "/ontology/eco/terms/%s";
    private static final String TAXONOMY_ID_NODE_RESOURCE_FORMAT = "/proteins/api/taxonomy/id/%s/node";
    private static final String BASE_URL = "https://localhost";
    private ObjectMapper dtoMapper = new ObjectMapper();
    private MockRestServiceServer mockRestServiceServer;

    StatsSetupHelper(
            MockRestServiceServer mockRestServiceServer) {
        this.mockRestServiceServer = mockRestServiceServer;
    }

    void expectRestCallSuccess(String url, String response) {
        mockRestServiceServer.expect(
                requestTo(BASE_URL + url))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withSuccess(response, MediaType.APPLICATION_JSON));
    }

    void expectGORestCallResponse(String id, ResponseCreator
            response) {
        mockRestServiceServer.expect(
                requestTo(BASE_URL + this.buildResource(GO_TERM_RESOURCE_FORMAT, id)))
                .andExpect(method(HttpMethod.GET))
                .andRespond(response);
    }

    void expectTaxonomyRestCallResponse(String id, ResponseCreator
            response) {
        mockRestServiceServer.expect(
                requestTo(BASE_URL + this.buildResource(TAXONOMY_ID_NODE_RESOURCE_FORMAT, id)))
                .andExpect(method(HttpMethod.GET))
                .andRespond(response);
    }

    void expectEcoRestCallResponse(String id, ResponseCreator
            response) {
        mockRestServiceServer.expect(
                requestTo(BASE_URL + this.buildResource(ECO_TERM_RESOURCE_FORMAT, id)))
                .andExpect(method(HttpMethod.GET))
                .andRespond(response);
    }

    void expectGoTermHasNameViaRest(String id, String name) {
        this.expectIdHasGivenResultViaOntologyRest(GO_TERM_RESOURCE_FORMAT, id, name);
    }

    void expectGoTermHasNameViaRest(int number) {
        for (int i = 0; i < number; i++) {
            this.expectIdHasGivenResultViaOntologyRest(GO_TERM_RESOURCE_FORMAT, goId(i), goName(i));
        }
    }

    void expectEcoCodeHasNameViaRest(String ecoId, String ecoTermName, int number) {
        for (int i = 0; i < number; i++) {
            this.expectIdHasGivenResultViaOntologyRest(ECO_TERM_RESOURCE_FORMAT, ecoId, ecoTermName);
        }
    }

    String goId(int id) {
        return IdGeneratorUtil.createGoId(id);
    }

    String goName(int id) {
        return IdGeneratorUtil.createGoId(id) + " name";
    }

    void expectTaxonIdHasNameViaRest(String id, String name) {
        String responseAsString = constructTaxonomyTermsResponseObject(name);
        this.expectRestCallSuccess(
                this.buildResource(TAXONOMY_ID_NODE_RESOURCE_FORMAT, id), responseAsString);
    }

    String[] expectedNames(int expectedSize, String source) {
        String[] names = new String[expectedSize];
        IntStream.range(0, names.length)
                .forEach(i -> names[i] = source);
        return names;
    }

    private void expectIdHasGivenResultViaOntologyRest(String resourceFormat, String id, String result) {
        this.expectRestCallSuccess(
                this.buildResource(resourceFormat, id),
                this.constructOntologyTermsResponseObject(id, result));
    }

    private String constructOntologyTermsResponseObject(String id, String termName) {
        BasicOntology response = new BasicOntology();
        List<BasicOntology.Result> results = new ArrayList<>();
        BasicOntology.Result result = new BasicOntology.Result();
        result.setId(id);
        result.setName(termName);
        results.add(result);
        response.setResults(results);
        return getResponseAsString(response);
    }

    private String constructTaxonomyTermsResponseObject(String name) {
        BasicTaxonomyNode expectedResponse = new BasicTaxonomyNode();
        expectedResponse.setScientificName(name);
        return this.getResponseAsString(expectedResponse);
    }

    private String buildResource(String format, String... arguments) {
        int requiredArgsCount = format.length() - format.replace("%", "").length();
        List<String> args = new ArrayList<>();
        for (int i = 0; i < requiredArgsCount; i++) {
            if (i < arguments.length) {
                args.add(arguments[i]);
            } else {
                args.add("");
            }
        }
        return String.format(format, args.toArray());
    }

    private <T> String getResponseAsString(T response) {
        try {
            return dtoMapper.writeValueAsString(response);
        } catch (JsonProcessingException e) {
            throw new IllegalStateException("Problem constructing mocked GO term REST response:", e);
        }
    }
}

@@ -1709,23 +1709,16 @@
 RestCall
-Success
 (String 
@@ -1722,22 +1722,31 @@
 ng url, 
-String
+ResponseCreator
  respons
@@ -1914,57 +1914,16 @@
 ond(
-withSuccess(response, MediaType.APPLICATION_JSON)
+response
 );%0A 
@@ -1984,36 +1984,24 @@
 ponseCreator
-%0A           
  response) %7B
@@ -2285,36 +2285,24 @@
 ponseCreator
-%0A           
  response) %7B
@@ -2594,28 +2594,16 @@
 eCreator
-%0A           
  respons
@@ -3776,39 +3776,32 @@
 s.expectRestCall
-Success
 (%0A              
@@ -3860,16 +3860,28 @@
 T, id), 
+withSuccess(
 response
@@ -3888,16 +3888,70 @@
 AsString
+, MediaType%0A                        .APPLICATION_JSON)
 );%0A    %7D
@@ -4318,23 +4318,16 @@
 RestCall
-Success
 (%0A      
@@ -4388,24 +4388,36 @@
             
+withSuccess(
 this.constru
@@ -4457,16 +4457,70 @@
  result)
+, MediaType%0A                        .APPLICATION_JSON)
 );%0A    %7D

Make the base expectRestCallSuccess take a ResponseCreator, rather than a String.