/*
 * 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.infrastructure.votingcardset;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import retrofit2.Retrofit;

import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.io.InputStream;

import com.scytl.products.ov.commons.infrastructure.exception.OvCommonsInfrastructureException;
import com.scytl.products.ov.commons.infrastructure.remote.client.InputStreamTypedOutput;
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.domain.model.votingcardset.VotingCardSetUploadRepository;
import com.scytl.products.ov.sdm.infrastructure.clients.ExtendedAuthenticationClient;
import com.scytl.products.ov.sdm.infrastructure.clients.VoterMaterialClient;
import com.scytl.products.ov.sdm.infrastructure.exception.VotingCardSetUploadRepositoryException;

import okhttp3.ResponseBody;

import static java.text.MessageFormat.format;

/**
 * implementation of the repository using a REST CLIENT
 */
@Repository
public class VotingCardSetUploadRepositoryImpl
        implements VotingCardSetUploadRepository {

	private static final MediaType TEXT_CSV_TYPE = new MediaType("text", "csv");
	
	private static final int STATUS_OK = 200;

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

    private final VoterMaterialClient voterMaterialClient;

    private final ExtendedAuthenticationClient extendedAuthenticationClient;

    @Autowired
    public VotingCardSetUploadRepositoryImpl(@Value("${VM_URL}") String voterMaterialURL,
                                             @Value("${EA_URL}") String extendedAuthenticationURL,
                                             @Value("${connection.time.out}") String connectionTimeOut,
                                             @Value("${read.time.out}") String readTimeOut,
                                             @Value("${write.time.out}") String writeTimeOut) {

        setTimeouts(connectionTimeOut, readTimeOut, writeTimeOut);
        voterMaterialClient = getVoterMaterialClient(voterMaterialURL);
        extendedAuthenticationClient = getExtendedAuthenticationClient(extendedAuthenticationURL);
    }

    private void handleErrorResponse(final RetrofitException response)
        throws IOException {
        final int status = response.getHttpCode();
        if (status != STATUS_OK) {
        	String message = "unknown";
        	if(response.getErrorBody()!= null){
        		message = response.getErrorBody().string();
        	}
            throw new IOException(format(
                "Operation failed with code ''{0}'' and reason ''{1}'', .",
                status, message));
        }
    }

    @Override
    public void uploadVoterInformation(final String electionEventId,
                                       final String votingCardSetId, final String adminBoardId,
                                       final InputStream stream) throws IOException {
        InputStreamTypedOutput body = new InputStreamTypedOutput(TEXT_CSV_TYPE.toString(), stream);
		try (ResponseBody responseBody = RetrofitConsumer.processResponse(voterMaterialClient
				.saveVoterInformationData(tenantId, electionEventId, votingCardSetId, adminBoardId, body))) {
			//This block is intentionally left blank for the use of Closeable 
		} catch (RetrofitException e) {
			handleErrorResponse(e);
		}
    }

    @Override
    public void uploadCredentialData(final String electionEventId,
                                     final String votingCardSetId, final String adminBoardId,
                                     final InputStream stream) throws IOException {
        InputStreamTypedOutput body = new InputStreamTypedOutput(TEXT_CSV_TYPE.toString(), stream);
		try (ResponseBody responseBody = RetrofitConsumer.processResponse(voterMaterialClient
				.saveCredentialData(tenantId, electionEventId, votingCardSetId, adminBoardId, body))) {
			//This block is intentionally left blank for the use of Closeable 
		} catch (RetrofitException e) {
			handleErrorResponse(e);
		}
    }

    @Override
    public void uploadExtendedAuthData(final String electionEventId, final String adminBoardId, final InputStream stream)
            throws IOException {
        InputStreamTypedOutput body = new InputStreamTypedOutput(TEXT_CSV_TYPE.toString(), stream);
		try (ResponseBody responseBody = RetrofitConsumer.processResponse(extendedAuthenticationClient
				.saveExtendedAuthenticationData(tenantId, electionEventId, adminBoardId, body))) {
			//This block is intentionally left blank for the use of Closeable 
	    } catch (RetrofitException e) {
			handleErrorResponse(e);
		}
    }

    private VoterMaterialClient getVoterMaterialClient(final String voterMaterialURL) {
        try {
            Retrofit restAdapter = RestClientConnectionManager.getInstance().getRestClientWithJacksonConverter(voterMaterialURL);
            return restAdapter.create(VoterMaterialClient.class);
        } catch (OvCommonsInfrastructureException e) {
            throw new VotingCardSetUploadRepositoryException("Error trying to get Voter Material Client.", e);
        }
    }

    private ExtendedAuthenticationClient getExtendedAuthenticationClient(final String extendedAuthenticationURL) {
        try {
            Retrofit restAdapter = RestClientConnectionManager.getInstance().getRestClientWithJacksonConverter(extendedAuthenticationURL);
            return restAdapter.create(ExtendedAuthenticationClient.class);
        } catch (OvCommonsInfrastructureException e) {
            throw new VotingCardSetUploadRepositoryException("Error trying to get Extended Authentication Client.", e);
        }
    }

    private void setTimeouts(String connectionTimeOut, String readTimeOut, String writeTimeOut) {
        System.setProperty("connection.time.out", connectionTimeOut);
        System.setProperty("read.time.out", readTimeOut);
        System.setProperty("write.time.out", writeTimeOut);
    }

}