/*
 * 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.vv.ui.ws.rs.application.operation;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.junit.Before;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.cryptolib.derivation.cryptoapi.CryptoAPIKDFDeriver;
import com.scytl.cryptolib.derivation.cryptoapi.CryptoAPIPBKDFDeriver;
import com.scytl.cryptolib.ffc.cryptoapi.FFCEngine;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomBytes;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomInteger;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomString;
import com.scytl.products.ov.commons.beans.domain.model.confirmation.TraceableConfirmationMessage;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.dto.CastCodeAndComputeResults;
import com.scytl.products.ov.commons.dto.ChoiceCodeAndComputeResults;
import com.scytl.products.ov.commons.dto.VoteAndComputeResults;
import com.scytl.products.ov.vv.service.CastCodeService;
import com.scytl.products.ov.vv.service.ChoiceCodesService;

public class VoteVerificationArquillianTest {

    @PersistenceContext(unitName = "persistenceUnitJdbc")
    protected EntityManager entityManager;

    @Resource
    UserTransaction userTransaction;

    protected int STATUS_OK = 200;

    protected static final String CHOICE_CODE_VALUE = "45611111111111111111111110";

    protected static final String ELECTION_EVENT_ID = "67cd59d8183f47a3a4cc64abfcc2916b";

    protected static final String TENANT_ID = "100";

    protected static final String CAST_CODE_MESSAGE_SIGNATURE = "test-signature";

    @Before
    public void cleanDatabase()
            throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException,
            HeuristicMixedException, HeuristicRollbackException {
        userTransaction.begin();
        entityManager.createQuery("delete from Verification").executeUpdate();
        entityManager.createQuery("delete from VerificationSetEntity").executeUpdate();
        entityManager.createQuery("delete from ElectoralAuthorityEntity").executeUpdate();
        entityManager.createQuery("delete from VerificationContentEntity ").executeUpdate();
        entityManager.createQuery("delete from CodesMappingEntity ").executeUpdate();
        userTransaction.commit();
    }

    protected String addPathValues(String path, String... parameterValues) {
        for (int i = 0; i < parameterValues.length; i += 2) {
            path = path.replace("{" + parameterValues[i] + "}", parameterValues[i + 1]);
        }
        return path;
    }

    public static class CastCodeServiceMockImpl implements CastCodeService {

        @Override
        public CastCodeAndComputeResults retrieveCastCodeAndSignature(String tenantId, String eeid,
                String verificationCardId, TraceableConfirmationMessage confirmationMessage)
                throws ResourceNotFoundException, CryptographicOperationException, ClassNotFoundException, IOException {
            CastCodeAndComputeResults castCodeMessage = new CastCodeAndComputeResults();
            castCodeMessage.setSignature(CAST_CODE_MESSAGE_SIGNATURE);
            castCodeMessage.setVoteCastCode("testVoteCastCode");
            return castCodeMessage;
        }
    }

    public static class PrimitivesServiceMock implements PrimitivesServiceAPI {

        @Override
        public CryptoAPIRandomString get32CharAlphabetCryptoRandomString() {
            return null;
        }

        @Override
        public CryptoAPIRandomString get64CharAlphabetCryptoRandomString() {
            return null;
        }

        @Override
        public CryptoAPIRandomBytes getCryptoRandomBytes() {
            return null;
        }

        @Override
        public CryptoAPIRandomInteger getCryptoRandomInteger() {
            return null;
        }

        @Override
        public FFCEngine getFFCEngine() {
            return null;
        }

        @Override
        public byte[] getHash(byte[] arg0) throws GeneralCryptoLibException {
            return new byte[0];
        }

        @Override
        public byte[] getHash(InputStream arg0) throws GeneralCryptoLibException {
            return null;
        }

        @Override
        public CryptoAPIKDFDeriver getKDFDeriver() {
            return null;
        }

        @Override
        public CryptoAPIPBKDFDeriver getPBKDFDeriver() {
            return null;
        }

        @Override
        public MessageDigest getRawMessageDigest() {
            return null;
        }

        @Override
        public void shuffle(List<?> arg0) throws GeneralCryptoLibException {

        }
    }

    public static class ChoiceCodesServiceMockImpl implements ChoiceCodesService {

        @Override
        public ChoiceCodeAndComputeResults generateChoiceCodes(String tenantId, String electionEventId,
                String verificationCardId, VoteAndComputeResults vote)
                throws ResourceNotFoundException, CryptographicOperationException {
            ChoiceCodeAndComputeResults choiceCode = new ChoiceCodeAndComputeResults();
            choiceCode.setChoiceCodes(CHOICE_CODE_VALUE);
            return choiceCode;
        }
    }

    protected <T> T getSavedObject(Class<T> clazz, String fieldName, String fieldValue) {

        Query query =
            entityManager.createQuery("from " + clazz.getName() + " where " + fieldName + " = :" + fieldName + " ")
                .setParameter(fieldName, fieldValue);
        T resultObject = clazz.cast(query.getSingleResult());

        return resultObject;
    }

}
