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

import com.scytl.products.ov.commons.verify.CryptolibPayloadSigningCertificateValidator;
import com.scytl.products.ov.commons.verify.PayloadSigningCertificateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.elgamal.ElGamalServiceAPI;
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.asymmetric.service.AsymmetricService;
import com.scytl.cryptolib.elgamal.service.ElGamalService;
import com.scytl.cryptolib.primitives.service.PrimitivesService;
import com.scytl.cryptolib.proofs.service.ProofsService;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.commons.sign.MetadataFileSigner;
import com.scytl.products.ov.commons.util.ConfigObjectMapper;
import com.scytl.products.ov.commons.verify.CryptolibPayloadVerifier;
import com.scytl.products.ov.commons.verify.PayloadVerifier;
import com.scytl.products.ov.mixnet.BGMixnetLoadBalancer;
import com.scytl.products.ov.mixnet.BGVerifier;
import com.scytl.products.ov.mixnet.BallotDecryptionService;
import com.scytl.products.ov.mixnet.MixnetLoadBalancer;
import com.scytl.products.ov.mixnet.SimpleBallotDecryptionService;
import com.scytl.products.ov.mixnet.api.MixingService;
import com.scytl.products.ov.mixnet.api.MixingServiceAPI;
import com.scytl.products.ov.mixnet.api.VerifyingService;
import com.scytl.products.ov.mixnet.api.VerifyingServiceAPI;
import com.scytl.products.ov.mixnet.commons.io.JSONProofsReader;
import com.scytl.products.ov.mixnet.commons.validation.EncryptedBallotsDuplicationValidator;
import com.scytl.products.ov.mixnet.mvc.MixingController;
import com.scytl.products.ov.mixnet.mvc.VerifyingController;
import com.scytl.products.ov.mixnet.webapp.mvc.MixDecValController;
import com.scytl.products.ov.validation.ValidationController;
import com.scytl.products.ov.validation.decompress.GroupElementDecompressor;
import com.scytl.products.ov.validation.decompress.VoteValidator;
import com.scytl.products.ov.validation.services.ValidationService;
import com.scytl.products.ov.validation.services.ValidationServiceImpl;
import com.scytl.products.ov.validation.services.input.VoteWithProofEntryParser;
import com.scytl.products.ov.validation.services.input.VotesWithProofReader;

/**
 * MixDecValController bean for tests.
 */
@Configuration
class CryptoServiceTestConfig {

    @Autowired
    private SecureLoggingWriter secureLogger;

    @Autowired
    private TransactionInfoProvider transactionInfoProvider;

    @Bean
    BallotDecryptionService ballotDecryptionService(TransactionInfoProvider transactionInfoProvider,
            PrimitivesServiceAPI primitivesService, ElGamalServiceAPI elGamalService, ProofsServiceAPI proofsService,
            SecureLoggingWriter secureLogger) {
        return new SimpleBallotDecryptionService(transactionInfoProvider, primitivesService, elGamalService,
            proofsService, secureLogger);
    }

    @Bean
    MixingController mixingController(MixingServiceAPI mixingService) throws GeneralCryptoLibException {
        return new MixingController(mixingService, transactionInfoProvider);
    }

    @Bean
    VerifyingController verifyingController(VerifyingServiceAPI verifyingService) {
        return new VerifyingController(verifyingService);
    }

    @Bean
    ValidationController validationController(ValidationService validationService) throws GeneralCryptoLibException {
        return new ValidationController(validationService);
    }

    @Bean
    ValidationService validationService(VotesWithProofReader votesWithProofReader,
            GroupElementDecompressor groupElementDecompressor, VoteValidator voteValidator,
            PrimitivesServiceAPI primitivesService, SecureLoggingWriter secureLogger,
            TransactionInfoProvider transactionInfoProvider, MetadataFileSigner metadataFileSigner) {
        return new ValidationServiceImpl(votesWithProofReader, groupElementDecompressor, voteValidator,
            primitivesService, secureLogger, transactionInfoProvider, metadataFileSigner);
    }

    @Bean
    MetadataFileSigner metadataFileSigner(AsymmetricServiceAPI asymmetricService) {
        return new MetadataFileSigner(asymmetricService);
    }

    @Bean
    VoteValidator voteValidator() {
        return new VoteValidator();
    }

    @Bean
    GroupElementDecompressor groupElementDecompressor() {
        return new GroupElementDecompressor();
    }

    @Bean
    ConfigObjectMapper objectMapper() {
        return new ConfigObjectMapper();
    }

    @Bean
    VotesWithProofReader votesWithProofReader(VoteWithProofEntryParser entryParser, SecureLoggingWriter secureLogger) {
        return new VotesWithProofReader(entryParser, secureLogger);
    }

    @Bean
    VerifyingServiceAPI verifyingService(BGVerifier bgVerifier) {
        return new VerifyingService(bgVerifier);
    }

    @Bean
    MixDecValController mixDecValController() {
        return new MixDecValController();
    }

    @Bean
    MixingServiceAPI mixingService(MixnetLoadBalancer mixnetLoadBalancer) {
        return new MixingService(mixnetLoadBalancer);
    }

    @Bean
    PrimitivesServiceAPI primitivesService() throws GeneralCryptoLibException {
        return new PrimitivesService();
    }

    @Bean
    AsymmetricServiceAPI AsymmetricService() throws GeneralCryptoLibException {
        return new AsymmetricService();
    }

    @Bean
    ElGamalServiceAPI elGamalService() throws GeneralCryptoLibException {
        return new ElGamalService();
    }

    @Bean
    ProofsServiceAPI proofsService() throws GeneralCryptoLibException {
        return new ProofsService();
    }

    @Bean
    BGVerifier bgVerifier(SecureLoggingWriter secureLogger) {
        return new BGVerifier(secureLogger);
    }

    @Bean
    JSONProofsReader proofsReader() {
        return new JSONProofsReader();
    }

    @Bean
    VoteWithProofEntryParser entryParser(ConfigObjectMapper objectMapper) {
        return new VoteWithProofEntryParser(objectMapper);
    }

    @Bean
    PayloadVerifier payloadVerifier(AsymmetricServiceAPI asymmetricService,
            PayloadSigningCertificateValidator certificateValidator) {
        return new CryptolibPayloadVerifier(asymmetricService, certificateValidator);
    }

    @Bean
    PayloadSigningCertificateValidator certificateValidator() {
        return new CryptolibPayloadSigningCertificateValidator();
    }

    @Bean
    public MixnetLoadBalancer balancer(PrimitivesServiceAPI primitivesService,
            BallotDecryptionService ballotDecryptionService, TransactionInfoProvider transactionInfoProvider,
            SecureLoggingWriter loggingWriter) {
        return new BGMixnetLoadBalancer.Builder().setPrimitivesService(primitivesService)
            .setBallotDecryptionService(ballotDecryptionService).setTransactionInfoProvider(transactionInfoProvider)
            .setLoggingWriter(loggingWriter).addBallotsValidator(new EncryptedBallotsDuplicationValidator()).build();
    }
}
