/*
 * 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.ei.services.domain.service.vote;

import java.io.IOException;

import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;
import javax.json.JsonObject;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.ov.commons.beans.domain.model.receipt.Receipt;
import com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.exceptions.ValidationException;
import com.scytl.products.ov.commons.logging.I18nLoggerMessages;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBox;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogConstants;
import com.scytl.products.ov.ei.services.infrastructure.log.ElectionInformationLogEvents;
import com.scytl.products.ov.ei.services.infrastructure.log.SecureLoggerHelper;

/**
 * Decorator of the validation service.
 */
@Decorator
public abstract class VoteValidationServiceDecorator implements VoteValidationService {

    private static final String VOTE = "vote";

    private static final String RECEIPT = "receipt";

    @Inject
    @Delegate
    private VoteValidationService validationService;

    @Inject
    private TrackIdInstance trackId;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    private static final Logger LOG = LoggerFactory.getLogger("std");

    private static final I18nLoggerMessages I18N = I18nLoggerMessages.getInstance();

    @Inject
    private SecureLoggerHelper secureLoggerHelper;

    /**
     * @see com.scytl.products.ov.ei.services.domain.service.vote.VoteValidationService#validate(com.scytl.products.ov.ei.services.domain.model.vote.Vote,
     *      java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public ValidationResult validate(Vote vote, String tenantId, String electionEventId, String ballotId)
            throws ApplicationException, ResourceNotFoundException {
        LOG.info(I18N.getMessage("ValidationServiceImpl.validate.startVoteValidation"), tenantId, ballotId);

        ValidationResult validationResult = validationService.validate(vote, tenantId, electionEventId, ballotId);
        String voteHash = secureLoggerHelper.getVoteHash(vote);
        if (validationResult.isResult()) {
            LOG.info(I18N.getMessage("ValidationServiceImpl.validate.voteValid"), validationResult.isResult());
            String authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.VOTE_VALID)
                    .objectId(authTokenHash).user(vote.getVotingCardId()).electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash).createLogInfo());
        } else {
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.VOTE_INVALID)
                    .objectId(vote.getVerificationCardId()).user(vote.getVerificationCardId())
                    .electionEvent(vote.getElectionEventId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                    .additionalInfo(ElectionInformationLogConstants.INFO_VERIFICATION_CARD_ID,
                        vote.getVerificationCardId())
                    .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC,
                        ElectionInformationLogEvents.VOTE_INVALID.getInfo())
                    .createLogInfo());
        }

        LOG.info(I18N.getMessage("ValidationServiceImpl.validate.endVoteValidation"));
        return validationResult;
    }

    @Override
    public boolean isValid(BallotBox ballotBox) throws ValidationException {
        try {
            return validationService.isValid(ballotBox);
        } catch (ValidationException e) {
            JsonObject voteJsonObject = JsonUtils.getJsonObject(ballotBox.getVote());
            Vote vote = null;
            Receipt receipt = null;
            try {
                vote = ObjectMappers.fromJson(voteJsonObject.get(VOTE).toString(), Vote.class);
                receipt = ObjectMappers.fromJson(voteJsonObject.get(RECEIPT).toString(), Receipt.class);
            } catch (IOException ioE) {
                LOG.error("Error processing the vote or the receipt.", ioE);
            }
            
            String authTokenHash;
            String voteHash;
            String receiptReceipt;
            
			if (vote != null) {
				authTokenHash = secureLoggerHelper.getAuthTokenHash(vote.getAuthenticationToken());
				voteHash = secureLoggerHelper.getVoteHash(vote);
			} else {
				authTokenHash = null;
				voteHash = null;
			}

			if (receipt != null) {
				receiptReceipt = receipt.getReceipt();
			} else {
				receiptReceipt = null;
			}
            
            secureLoggerWriter
                .log(Level.ERROR,
                    new LogContent.LogContentBuilder().logEvent(ElectionInformationLogEvents.VOTE_INVALID)
                        .objectId(authTokenHash).user(ballotBox.getVotingCardId())
                        .electionEvent(ballotBox.getElectionEventId())
                        .additionalInfo(ElectionInformationLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                        .additionalInfo(ElectionInformationLogConstants.INFO_HASH_VOTE, voteHash)
                        .additionalInfo(ElectionInformationLogConstants.INFO_RECEIPT, receiptReceipt)
                        .additionalInfo(ElectionInformationLogConstants.INFO_ERR_DESC,
                            "Error saving the vote and receipt: " + ExceptionUtils.getRootCauseMessage(e))
                        .createLogInfo());
            throw e;
        }
    }
}
