/*
 * 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 java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.scytl.products.oscore.logging.api.domain.Level;
import com.scytl.products.oscore.logging.api.domain.LogContent;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.sdm.application.log.SdmSecureLogEvent;
import com.scytl.products.ov.sdm.application.service.AdminBoardUploadService;
import com.scytl.products.ov.sdm.application.service.BallotBoxInformationsUploadService;
import com.scytl.products.ov.sdm.application.service.BallotUploadService;
import com.scytl.products.ov.sdm.application.service.ElectoralAuthoritiesUploadService;
import com.scytl.products.ov.sdm.application.service.KeyStoreService;
import com.scytl.products.ov.sdm.application.service.KeyTranslationUploadService;
import com.scytl.products.ov.sdm.application.service.VotingCardSetUploadService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/**
 * The configuration upload end-point.
 */
@RestController
@RequestMapping("/sdm-ws-rest/configurations")
@Api(value = "Configurations REST API", description = "")
public class ConfigurationResource {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationResource.class);

    private static final String NULL_ELECTION_EVENT_ID = "";

    @Autowired
    private BallotUploadService ballotUploadService;

    @Autowired
    private BallotBoxInformationsUploadService ballotBoxInformationsUploadService;

    @Autowired
    private VotingCardSetUploadService votingCardSetUploadService;

    @Autowired
    private ElectoralAuthoritiesUploadService electoralAuthoritiesUploadService;

    @Autowired
    private AdminBoardUploadService adminBoardUploadService;

    @Autowired
    private KeyTranslationUploadService keyTranslationUploadService;

    @Value("${voting.portal.enabled}")
    private boolean isVoterPortalEnabled;

    @Autowired
    private KeyStoreService keystoreService;

    @Autowired
    private TransactionInfoProvider transactionInfoProvider;

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

    @Autowired
    SecureLoggingWriter secureLogger;

    /**
     * Uploads data to all election events (not yet synchronized)
     *
     * @throws IOException
     *             if something fails uploading voting card sets or electoral
     *             authorities.
     */
    @RequestMapping(method = RequestMethod.POST, produces = "application/json")
    @ResponseStatus(value = HttpStatus.OK)
    @ApiOperation(value = "Upload configuration", notes = "Service to upload the configuration.")
    public void uploadConfiguration() throws IOException {

        transactionInfoProvider.generate(tenantId, "", "");

        if (isVoterPortalEnabled) {
            uploadElectionEventData(NULL_ELECTION_EVENT_ID);
        } else {
            LOGGER.info(
                "The application is configured to not have connectivity to Voter Portal, check if this is the expected behavior");
        }
    }

    /**
     * Uploads data specific to one election event
     *
     * @throws IOException
     *             if something fails uploading voting card sets or electoral
     *             authorities.
     */
    @RequestMapping(value = "/electionevent/{electionEventId}", method = RequestMethod.POST, produces = "application/json")
    @ResponseStatus(value = HttpStatus.OK)
    @ApiOperation(value = "Election event upload configuration", notes = "Service to upload the configuration for a given election event.")
    public void uploadElectionEventConfigurationConfiguration(
            @ApiParam(value = "String", required = true) @PathVariable String electionEventId) throws IOException {

        transactionInfoProvider.generate(tenantId, "", "");

        if (isVoterPortalEnabled) {
            uploadElectionEventData(electionEventId);
        } else {
            LOGGER.warn(
                "The application is configured to not have connectivity to Voter Portal, check if this is the expected behavior");
        }
    }

    private void uploadElectionEventData(
            final @ApiParam(value = "String", required = true) @PathVariable String electionEventId)
            throws IOException {

        transactionInfoProvider.generate(tenantId, "", "");

        secureLogger.log(Level.INFO, new LogContent.LogContentBuilder()
            .logEvent(SdmSecureLogEvent.SYNCHRONIZING_WITH_VP).electionEvent(electionEventId).createLogInfo());

        LOGGER.info("Uploading the configuration of election event " + electionEventId);

        LOGGER.info("Uploading administration board certificates");
        adminBoardUploadService.uploadSyncronizableAdminBoards(electionEventId, keystoreService.getPrivateKey());
        LOGGER.info("Uploading ballots");
        ballotUploadService.uploadSyncronizableBallots(electionEventId);
        LOGGER.info("Uploading ballot boxes");
        ballotBoxInformationsUploadService.uploadSyncronizableBallotBoxInformations(electionEventId);
        LOGGER.info("Uploading voting card sets");
        votingCardSetUploadService.uploadSyncronizableVotingCardSets(electionEventId);
        LOGGER.info("Uploading electoral authorities");
        electoralAuthoritiesUploadService.uploadSyncronizableElectoralAuthorities(electionEventId);
        LOGGER.info("Uploading election key translation");
        keyTranslationUploadService.uploadElectionEventKeyTranslation(electionEventId);

        secureLogger.log(Level.INFO,
            new LogContent.LogContentBuilder().logEvent(SdmSecureLogEvent.SYNCHRONIZING_WITH_VP_COMPLETED_SUCCESSFULLY)
                .electionEvent(electionEventId).createLogInfo());

    }

}
