package com.voterapi.voter.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.voterapi.voter.domain.CandidateVoterView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.env.Environment;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class CandidateListService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private Environment environment;

    private RabbitTemplate rabbitTemplate;

    private DirectExchange directExchange;

    @Autowired
    public CandidateListService(Environment environment,
                                RabbitTemplate rabbitTemplate,
                                DirectExchange directExchange) {
        this.environment = environment;
        this.rabbitTemplate = rabbitTemplate;
        this.directExchange = directExchange;
    }

    /**
     * Produces HTTP GET request containing election
     * Candidate service returns a list of candidates
     * * @param election
     *
     * @return List of candidates
     */
    public List<CandidateVoterView> getCandidatesSyncHttp(String election) {
        String candidateServiceHostname = environment.getProperty("services.candidate.host");
        String candidateServicePort = environment.getProperty("services.candidate.port");
        String candidateContextPath = environment.getProperty("services.candidate.context-path");
        String candidateServiceResourceUrl = String.format("http://%s:%s/%s/candidates/search/findByElectionContains?election=%s&projection=candidateVoterView",
                candidateServiceHostname, candidateServicePort, candidateContextPath, election);

        RestTemplate restTemplate = restTemplate();

        ResponseEntity<PagedResources<CandidateVoterView>> responseEntity = restTemplate.exchange(
                candidateServiceResourceUrl, HttpMethod.GET, null,
                new ParameterizedTypeReference<PagedResources<CandidateVoterView>>() {
                });
        PagedResources<CandidateVoterView> resources = responseEntity.getBody();

        return new ArrayList(resources.getContent());
    }

    private RestTemplate restTemplate() {
        // reference: http://izeye.blogspot.com/2015/01/consume-spring-data-rest-hateoas-hal.html
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(new Jackson2HalModule());

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
        converter.setObjectMapper(mapper);
        return new RestTemplate(Arrays.asList(converter));
    }

    /**
     * Produces query message containing election
     * Consumes candidate list based on election query
     *
     * @param election
     * @return List of candidates
     */
    @SuppressWarnings("unchecked")
    public List<CandidateVoterView> getCandidatesMessageRpc(String election) {
        logger.debug("Sending RPC request message for list of candidates...");

        String requestMessage = election;
        String candidates = (String) rabbitTemplate.convertSendAndReceive(
                directExchange.getName(), "rpc", requestMessage);

        TypeReference<List<CandidateVoterView>> mapType =
                new TypeReference<List<CandidateVoterView>>() {};

        ObjectMapper objectMapper = new ObjectMapper();

        List<CandidateVoterView> candidatesList = null;
        try {
            candidatesList = objectMapper.readValue(candidates, mapType);
        } catch (IOException e) {
            logger.info(String.valueOf(e));
        }

        logger.debug("List of {} candidates received...", candidatesList.size());

        return candidatesList;
    }
}

@@ -1124,16 +1124,38 @@
 il.List;
+%0Aimport java.util.Map;
 %0A%0A@Servi
@@ -4221,32 +4221,44 @@
   TypeReference%3C
+Map%3CString, 
 List%3CCandidateVo
@@ -4266,16 +4266,17 @@
 erView%3E%3E
+%3E
  mapType
@@ -4312,16 +4312,28 @@
 ference%3C
+Map%3CString, 
 List%3CCan
@@ -4345,24 +4345,25 @@
 eVoterView%3E%3E
+%3E
 () %7B%7D;%0A%0A    
@@ -4422,16 +4422,28 @@
 %0A       
+ Map%3CString,
  List%3CCa
@@ -4459,16 +4459,17 @@
 terView%3E
+%3E
  candida
@@ -4471,20 +4471,19 @@
 ndidates
-List
+Map
  = null;
@@ -4483,16 +4483,17 @@
 = null;%0A
+%0A
         
@@ -4520,20 +4520,19 @@
 ndidates
-List
+Map
  = objec
@@ -4656,24 +4656,108 @@
 %0A        %7D%0A%0A
+        List%3CCandidateVoterView%3E candidatesList  = candidatesMap.get(%22candidates%22);%0A
         logg

Refactor code based on SonarQube SCA