/*
 * 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.orchestrator.choicecodes.domain.services;

import java.time.Duration;
import java.util.List;

import javax.ejb.Stateless;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;

import com.scytl.products.ov.channel.cc.orchestrator.commons.infrastructure.persistence.Jdbc;
import com.scytl.products.ov.channel.cc.orchestrator.commons.infrastructure.persistence.PartialResultsRepository;
import com.scytl.products.ov.channel.cc.orchestrator.commons.messaging.ResultsReadyListener;
import com.scytl.products.ov.channel.cc.orchestrator.commons.polling.PollingService;
import com.scytl.products.ov.channel.cc.orchestrator.commons.polling.PollingServiceImpl;
import com.scytl.products.ov.channel.cc.orchestrator.commons.polling.ReactivePartialResultsHandlerImpl;
import com.scytl.products.ov.channel.cc.orchestrator.commons.polling.ReactiveResultsHandler;
import com.scytl.products.ov.commons.messaging.MessageListener;

/**
 * CDI bean producer.
 */
@Stateless
public class ChoiceCodesBeanProducer {

    private static final Duration DECRYPTION_POLLING_TIMEOUT = getDuration(
        "decrypt_polling_timeout_ms", Duration.ofMillis(20000));

    private static final Duration DECRYPTION_INTER_POLLS_DELAY =
        getDuration("decrypt_inter_polls_delay_ms",
            Duration.ofMillis(100));

    private static final Duration COMPUTE_POLLING_TIMEOUT = getDuration(
        "compute_polling_timeout_ms", Duration.ofMillis(10000));

    private static final Duration COMPUTE_INTER_POLLS_DELAY = getDuration(
        "compute_inter_polls_delay_ms", Duration.ofMillis(100));

    private static final Duration KEY_GENERATION_POLLING_TIMEOUT =
        getDuration("choice_codes_key_generation_polling_timeout_ms",
            Duration.ofMillis(20000));

    private static final Duration KEY_GENERATION_INTER_POLLS_DELAY =
        getDuration("choice_codes_key_generation_inter_polls_delay_ms",
            Duration.ofMillis(100));

    private static Duration getDuration(String propertyName,
            Duration defaultValue) {
        String propertyValue = System.getProperty(propertyName);
        if (propertyValue == null) {
            return defaultValue;
        }
        return Duration.ofMillis(Long.parseLong(propertyValue));
    }

    @Produces
    @ApplicationScoped
    @ChoiceCodesVerification
    public ReactiveResultsHandler<List<byte[]>> verificationResultsHandler(
            @Jdbc PartialResultsRepository<byte[]> repository) {
        Duration timeout = COMPUTE_POLLING_TIMEOUT.multipliedBy(2);
        ReactivePartialResultsHandlerImpl<byte[]> handler =
            new ReactivePartialResultsHandlerImpl<>(repository, timeout);
        handler.start();
        return handler;
    }

    public void stopVerificationResultsHandler(
            @Disposes @ChoiceCodesVerification ReactiveResultsHandler<List<byte[]>> handler) {
        ((ReactivePartialResultsHandlerImpl<byte[]>) handler).stop();
    }

    @Produces
    @ChoiceCodesVerification
    public PollingService<List<byte[]>> verificationPollingService(
            @ChoiceCodesVerification ReactiveResultsHandler<List<byte[]>> handler) {
        return new PollingServiceImpl<>(handler, COMPUTE_POLLING_TIMEOUT,
            COMPUTE_INTER_POLLS_DELAY);
    }
    
    @Produces
    @ChoiceCodesVerification
    @ResultsReady
    public MessageListener verificationResultsReadyListener(
            @ChoiceCodesVerification ReactiveResultsHandler<List<byte[]>> handler) {
        return new ResultsReadyListener(handler);
    }
    
    @Produces
    @ApplicationScoped
    @ChoiceCodesDecryption
    public ReactiveResultsHandler<List<byte[]>> decryptionResultsHandler(
            @Jdbc PartialResultsRepository<byte[]> repository) {
        Duration timeout = DECRYPTION_POLLING_TIMEOUT.multipliedBy(2);
        ReactivePartialResultsHandlerImpl<byte[]> handler =
            new ReactivePartialResultsHandlerImpl<>(repository, timeout);
        handler.start();
        return handler;
    }

    public void stopDecryptionResultsHandler(
            @Disposes @ChoiceCodesDecryption ReactiveResultsHandler<List<byte[]>> handler) {
        ((ReactivePartialResultsHandlerImpl<byte[]>) handler).stop();
    }

    @Produces
    @ChoiceCodesDecryption
    public PollingService<List<byte[]>> decryptionPollingService(
            @ChoiceCodesDecryption ReactiveResultsHandler<List<byte[]>> handler) {
        return new PollingServiceImpl<>(handler,
            DECRYPTION_POLLING_TIMEOUT, DECRYPTION_INTER_POLLS_DELAY);
    }
    
    @Produces
    @ChoiceCodesDecryption
    @ResultsReady
    public MessageListener decryptionResultsReadyListener(
            @ChoiceCodesDecryption ReactiveResultsHandler<List<byte[]>> handler) {
        return new ResultsReadyListener(handler);
    }

    @Produces
    @ApplicationScoped
    @ChoiceCodesKeyGeneration
    public ReactiveResultsHandler<List<byte[]>> keyGenerationResultsHandler(
            @Jdbc PartialResultsRepository<byte[]> repository) {
        Duration timeout = KEY_GENERATION_POLLING_TIMEOUT.multipliedBy(2);
        ReactivePartialResultsHandlerImpl<byte[]> handler =
            new ReactivePartialResultsHandlerImpl<>(repository, timeout);
        handler.start();
        return handler;
    }

    public void stopKeyGenerationResultsHandler(
            @Disposes @ChoiceCodesKeyGeneration ReactiveResultsHandler<List<byte[]>> handler) {
        ((ReactivePartialResultsHandlerImpl<byte[]>) handler).stop();
    }


    @Produces
    @ChoiceCodesKeyGeneration
    public PollingService<List<byte[]>> keyGenerationPollingService(
            @ChoiceCodesKeyGeneration ReactiveResultsHandler<List<byte[]>> handler) {
        return new PollingServiceImpl<>(handler,
            KEY_GENERATION_POLLING_TIMEOUT,
            KEY_GENERATION_INTER_POLLS_DELAY);
    }
    
    @Produces
    @ChoiceCodesKeyGeneration
    @ResultsReady
    public MessageListener keyGenerationResultsReadyListener(
            @ChoiceCodesKeyGeneration ReactiveResultsHandler<List<byte[]>> handler) {
        return new ResultsReadyListener(handler);
    }
}
