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

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

import javax.json.JsonObject;
import javax.ws.rs.core.MediaType;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

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.verification.VerificationCardSetDataUploadRepository;
import com.scytl.products.ov.sdm.infrastructure.clients.VoteVerificationClient;
import com.scytl.products.ov.sdm.infrastructure.exception.VerificationCardSetUploadRepositoryException;

import okhttp3.ResponseBody;

import static java.text.MessageFormat.format;

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

    public static final String ADMIN_BOARD_ID_PARAM = "adminBoardId";

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

    private static final int STATUS_OK = 200;

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

    final VoteVerificationClient voteVerificationClient;

    @Autowired
    public VerificationCardSetUploadRepositoryImpl(@Value("${VV_URL}") String voteVerificationURL,
            @Value("${connection.time.out}") String connectionTimeOut, @Value("${read.time.out}") String readTimeOut,
            @Value("${write.time.out}") String writeTimeOut) {
        setTimeouts(connectionTimeOut, readTimeOut, writeTimeOut);
        voteVerificationClient = getVoteVerificationClient(voteVerificationURL);
    }

    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 uploadCodesMapping(String electionEventId, String verificationCardSetId, String adminBoardId,
            InputStream stream) throws IOException {
        InputStreamTypedOutput body = new InputStreamTypedOutput(TEXT_CSV_TYPE.toString(), stream);
		try (ResponseBody responseBody = RetrofitConsumer.processResponse(voteVerificationClient
				.saveCodesMappingData(tenantId, electionEventId, verificationCardSetId, adminBoardId, body))) {
            //This block is intentionally left blank for the use of Closeable 
        } catch (RetrofitException e) {
            handleErrorResponse(e);
        }
    }

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

    @Override
    public void uploadVerificationCardSetData(String electionEventId, String verificationCardSetId, String adminBoardId,
            JsonObject verificationCardSetData) throws IOException {

        InputStreamTypedOutput body = new InputStreamTypedOutput(MediaType.APPLICATION_JSON,
            new ByteArrayInputStream(verificationCardSetData.toString().getBytes(StandardCharsets.UTF_8)));
        try (ResponseBody responseBody =  RetrofitConsumer.processResponse(voteVerificationClient.saveVerificationCardSetData(tenantId,
                electionEventId, verificationCardSetId, adminBoardId, body))) {
            //This block is intentionally left blank for the use of Closeable 
        } catch (RetrofitException e) {
            handleErrorResponse(e);
        }
    }

    private VoteVerificationClient getVoteVerificationClient(final String voteVerificationURL) {
        try {
            Retrofit restAdapter =
                RestClientConnectionManager.getInstance().getRestClientWithJacksonConverter(voteVerificationURL);
            return restAdapter.create(VoteVerificationClient.class);
        } catch (OvCommonsInfrastructureException e) {
			throw new VerificationCardSetUploadRepositoryException("Error trying to get vote verification 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);
    }

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