/*
 * 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.channel.cc.commons.test;

import java.security.KeyManagementException;

import javax.sql.DataSource;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.cryptolib.api.proofs.ProofsServiceAPI;
import com.scytl.cryptolib.elgamal.bean.ElGamalPrivateKey;
import com.scytl.cryptolib.primitives.service.PrimitivesServiceFactoryHelper;
import com.scytl.cryptolib.proofs.service.ProofsService;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.channel.cc.choicecodes.generation.service.ChoiceCodesGenerationService;
import com.scytl.products.ov.channel.cc.choicecodes.generation.service.ChoiceCodesGenerationServiceImpl;
import com.scytl.products.ov.channel.cc.choicecodes.verification.service.ChoiceCodesComputationService;
import com.scytl.products.ov.channel.cc.choicecodes.verification.service.ChoiceCodesComputationServiceImpl;
import com.scytl.products.ov.channel.cc.choicecodes.verification.service.ComputedVerificationCardsRepository;
import com.scytl.products.ov.channel.cc.choicecodes.verification.service.ComputedVerificationCardsRepositoryImpl;
import com.scytl.products.ov.channel.cc.choicecodes.verification.service.ProofValidator;
import com.scytl.products.ov.channel.cc.commons.exponentiation.ExponentiationService;
import com.scytl.products.ov.channel.cc.commons.exponentiation.ExponentiationServiceImpl;
import com.scytl.products.ov.channel.cc.commons.keymanagement.KeyManager;
import com.scytl.products.ov.channel.cc.commons.services.ChoiceCodesKeyRepository;
import com.scytl.products.ov.channel.cc.commons.services.compute.KeyDerivationService;
import com.scytl.products.ov.channel.cc.commons.slogger.ServiceTransactionInfoProvider;
import com.scytl.products.ov.channel.cc.commons.util.FingerprintGenerator;
import com.scytl.products.ov.commons.beans.domain.model.messaging.PayloadSignature;
import com.scytl.products.ov.commons.beans.domain.model.messaging.PayloadSignatureException;
import com.scytl.products.ov.commons.beans.domain.model.messaging.PayloadVerificationException;
import com.scytl.products.ov.commons.dto.ElGamalComputationsValuesCodec;
import com.scytl.products.ov.commons.dto.ElGamalComputationsValuesCodecImpl;
import com.scytl.products.ov.commons.messaging.MessagingService;
import com.scytl.products.ov.commons.sign.PayloadSigner;
import com.scytl.products.ov.commons.verify.PayloadVerifier;

@Configuration
public class TestConfiguration {
    
    @Bean
    public SecureLoggingWriter secureLoggingWriter() {        
        return Mockito.mock(SecureLoggingWriter.class);
    }
    
    @Bean
    public KeyManager keyManager() {
        return Mockito.mock(KeyManager.class);
    }
    
    @Bean
    public MessagingService messagingService() {
        return new MessagingServiceMockImpl();
    }
    
    @Bean
    public ChoiceCodesGenerationService choiceCodesGenerationService() {
        return new ChoiceCodesGenerationServiceImpl();
    }
    
    @Bean
    public ChoiceCodesComputationService choiceCodesComputationService() {
        return new ChoiceCodesComputationServiceImpl();
    }
    
    @Bean
    public ExponentiationService exponentiationService(ProofsServiceAPI proofsService) {
        return new ExponentiationServiceImpl(proofsService);
    }
    
    @Bean
    public ProofsServiceAPI proofsService() throws GeneralCryptoLibException {
        return new ProofsService();
    }
    
    @Bean
    public ProofValidator proofValidator() {
        ProofValidator proofValidatorMock = Mockito.mock(ProofValidator.class);
        Mockito.when(proofValidatorMock.validate(Mockito.any(), Mockito.any())).thenReturn(true);
        return proofValidatorMock;
    }
    
    @Bean
    public PayloadVerifier payloadVerifier() throws PayloadVerificationException {
        PayloadVerifier payloadVerifierMock = Mockito.mock(PayloadVerifier.class);
        Mockito.when(payloadVerifierMock.isValid(Mockito.any(), Mockito.any())).thenReturn(true);
        return payloadVerifierMock;
    }
    
    @Bean
    public PayloadSigner payloadSigner() throws PayloadSignatureException {    
        PayloadSignature payloadSignatureMock = Mockito.mock(PayloadSignature.class);
        Mockito.when(payloadSignatureMock.getSignatureContents()).thenReturn(new byte[]{1});
        PayloadSigner payloadSignerMock = Mockito.mock(PayloadSigner.class);
        Mockito.when(payloadSignerMock.sign(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(payloadSignatureMock);
        return payloadSignerMock;
    }
    
    @Bean
    public ServiceTransactionInfoProvider serviceTransactionInfoProvider() {
        return new ServiceTransactionInfoProvider();
    }
    
    @Bean
    public PrimitivesServiceAPI primitivesService() {
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(50);
        try {
            return PrimitivesServiceFactoryHelper.getFactoryOfThreadSafeServices(config).create();
        } catch (GeneralCryptoLibException e) {
            throw new IllegalStateException("Exception while trying to create PrimitivesService", e);
        }
    }
    
    @Bean
    public KeyDerivationService keyDerivationService() {
        return new KeyDerivationService();
    }
    
    @Bean
    public ChoiceCodesKeyRepository choiceCodesKeyRepository()
            throws KeyManagementException, GeneralCryptoLibException {

        final String PRIVATE_KEY =
            "{\"privateKey\":{\"zpSubgroup\":{\"g\":\"Ag==\",\"p\":\"AIGt8wzizyJ8+ia716YgY4FjG5gJRjfz+iB3OeWEMLCOLnoWG0wHwFQyo2VNx4lgBPDmSIb5NtJ/12U3dfe7JdgYjEMSaz9HUrfowHNwCuD1VVmDXxUvyxPSV5/iss7a85sopvR9n09imvvp8XDfPNuccd10TQwGSKVt2vN7vSMrgQOsGEuBBsEmsdlRil4+x9NTYphsc/7vTV9pRN4U+ZI5yTbBof6SFcH5mwAatlZB/RztwA1wh3qUUgyLz/kTKqTRbaPc5W1+LDPBZnMiaTWq786418pio4oM86mVIthfE/34S0kn8GpJGzNF12NzbVQzbpv6YpmrPKG1FfaQPwc=\",\"q\":\"QNb5hnFnkT59E13r0xAxwLGNzASjG/n9EDuc8sIYWEcXPQsNpgPgKhlRsqbjxLACeHMkQ3ybaT/rspu6+92S7AxGIYk1n6OpW/RgObgFcHqqrMGvipfliekrz/FZZ215zZRTej7Pp7FNffT4uG+ebc447romhgMkUrbteb3ekZXAgdYMJcCDYJNY7KjFLx9j6amxTDY5/3emr7Sibwp8yRzkm2DQ/0kK4PzNgA1bKyD+jnbgBrhDvUopBkXn/ImVUmi20e5ytr8WGeCzOZE0mtV351xr5TFRxQZ51MqRbC+J/vwlpJP4NSSNmaLrsbm2qhm3Tf0xTNWeUNqK+0gfgw==\"},\"exponents\":[\"DWOyiVH88d/gzjBCQZenbbstssyQKlHOo5+dpbZ3OV2Wko8K39cqCTHZmn1xXmFWSm/GIN6oI0IzMFHRdECGuFgEzF6a+SbYijtJyp2IodHvLvbul7ZSEj5Z1m4giGrQ+NWppu3kHZzP6u1gu7sY4BF3sAwT9rGPZrc9HadMdXspip5dxUVv30y0jTUenbksfUh/CoIpCxQXSMhIqYYZv/bK9RAKVwo1L3QeiucpefqF/14/4Li/idsskvkrsfOHixNJ2j3UV5zvPNrfyRA3oLxi1Ci9DDeQ3S12Svg9mzrKuuU0TXGwx509YubAi3fz6uUyi24tQCVmjQZ5ZGGeNA==\"]}}";
        ElGamalPrivateKey elGamalPrivateKey = ElGamalPrivateKey.fromJson(PRIVATE_KEY);

        ChoiceCodesKeyRepository keyRepositoryMock = Mockito.mock(ChoiceCodesKeyRepository.class);
        Mockito.when(keyRepositoryMock.getGenerationPrivateKey(Mockito.anyString(), Mockito.anyString()))
            .thenReturn(elGamalPrivateKey);

        return keyRepositoryMock;
    }

    @Bean
    public ElGamalComputationsValuesCodec elGamalComputationsValuesCodec() {
        return ElGamalComputationsValuesCodecImpl.getInstance();
    }
    
    @Bean
    public FingerprintGenerator getFingerprintGenerator(PrimitivesServiceAPI primitivesService) {
        return new FingerprintGenerator(primitivesService);
    }
    
    @Bean
    @Qualifier("TransactionAware")
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.H2)
            .setScriptEncoding("UTF-8").ignoreFailedDrops(true).addScript("sql/oracle/V1538408870__create_computed_vcs_table.sql")
            .addScript("sql/oracle/V1539249503__add_computed_vcs_cast_attemps_column.sql").build();
    }
    
    @Bean
    public ComputedVerificationCardsRepository computedVerificationCardsRepository() {
        return new ComputedVerificationCardsRepositoryImpl();
    }
    
}