/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.sdm.application.service;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.scytl.products.ov.commons.infrastructure.exception.OvCommonsInfrastructureException;
import com.scytl.products.ov.commons.infrastructure.remote.client.RestClientConnectionManager;
import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitConsumer;
import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitException;
import com.scytl.products.ov.sdm.application.exception.ChoiceCodesComputationServiceException;
import com.scytl.products.ov.sdm.domain.model.status.Status;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;
import com.scytl.products.ov.sdm.infrastructure.cc.ChoiceCodeGenerationRequestPayloadRepository;
import com.scytl.products.ov.sdm.infrastructure.cc.PayloadStorageException;
import com.scytl.products.ov.sdm.infrastructure.clients.OrchestratorClient;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import okhttp3.ResponseBody;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import retrofit2.Response;
import retrofit2.Retrofit;

@Service
public class ChoiceCodesComputationService {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(ChoiceCodesComputationService.class);
	
    @Autowired
    private VotingCardSetRepository votingCardSetRepository;
    
    @Autowired
    private ChoiceCodeGenerationRequestPayloadRepository choiceCodeGenerationRequestPayloadRepository;

    @Value("${OR_URL}")
    private String orchestratorUrl;

    @Value("${tenantID}")
    private String tenantId;

    /**
     * Check if the choice code contributions for generation are ready and
     * update the status of the voting card set they belong to.
     *
     * @throws RetrofitException
     */
    public void updateChoiceCodesComputationStatus(final String electionEventId) throws IOException, RetrofitException {
        Map<String, Object> votingCardSetsParams = new HashMap<>();
        votingCardSetsParams.put(JsonConstants.JSON_ATTRIBUTE_NAME_STATUS, Status.COMPUTING.name());
        votingCardSetsParams.put(JsonConstants.JSON_STRUCTURE_NAME_ELECTION_EVENT_ID, electionEventId);

        String votingCardSetJSON = votingCardSetRepository.list(votingCardSetsParams);
        JsonArray votingCardSets = new JsonParser().parse(votingCardSetJSON).getAsJsonObject()
            .get(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT).getAsJsonArray();

        for (int i = 0; i < votingCardSets.size(); i++) {
            JsonObject votingCardSetInArray = votingCardSets.get(i).getAsJsonObject();
            String verificationCardSetId =
                votingCardSetInArray.get(JsonConstants.JSON_ATTRIBUTE_NAME_VERIFICATIONCARDSETID).getAsString();

            int chunkCount;
            try {
                chunkCount = choiceCodeGenerationRequestPayloadRepository.getCount(electionEventId, verificationCardSetId);
            } catch (PayloadStorageException e) {
                throw new IllegalStateException(e);
            }
            
            Response<ResponseBody> choiceCodesComputationStatusResponse =
                RetrofitConsumer.executeCall(getOrchestratorClient().getChoiceCodesComputationStatus(tenantId,
                    electionEventId, verificationCardSetId, chunkCount));

            JsonObject jsonObject;
            try (ResponseBody body = choiceCodesComputationStatusResponse.body(); Reader reader = body.charStream()) {
                jsonObject = new JsonParser().parse(reader).getAsJsonObject();
            }

            votingCardSetInArray.addProperty(JsonConstants.JSON_ATTRIBUTE_NAME_STATUS,
                jsonObject.get("status").getAsString());
            votingCardSetRepository.update(votingCardSetInArray.toString());
        }
    }

    /**
     * Gets the orchestrator Retrofit client
     */
    private OrchestratorClient getOrchestratorClient() {
        try {
            Retrofit restAdapter =
                RestClientConnectionManager.getInstance().getRestClientWithJacksonConverter(orchestratorUrl);
            return restAdapter.create(OrchestratorClient.class);
        } catch (OvCommonsInfrastructureException e) {
        	LOGGER.error("Error trying to get a RestClientConnectionManager instance.");
            throw new ChoiceCodesComputationServiceException(e);
        }
    }
}
