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

import java.io.IOException;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;

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.VoteRepositoryException;
import com.scytl.products.ov.commons.dto.CastCodeAndComputeResults;
import com.scytl.products.ov.commons.dto.VoteAndComputeResults;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.vw.infrastructure.log.VotingWorkflowLogConstants;
import com.scytl.products.ov.vw.infrastructure.log.VotingWorkflowLogEvents;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationToken;
import com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastMessage;
import com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastResult;
import com.scytl.products.ov.vw.services.domain.model.confirmation.VoteMessage;
import com.scytl.products.ov.vw.services.domain.model.vote.VoteRepository;

/**
 * Service for handling vote cast codes.
 */
@Stateless
public class VoteCastCodeService {

    @EJB
    private VoteRepository voteRepository;

    @Inject
    private TrackIdInstance trackIdInstance;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

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

    /**
     * Generates vote cast result with valid=true, vote message, encypted vote,
     * receipt message, auth token, vote cast message.
     *
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @param verificationCardId
     * @param castCodeComputeResults
     *            the vote cast message
     * @return the vote cast result
     * @throws ResourceNotFoundException
     *             if the vote can not be found.
     * @throws IOException
     *             if there are problems converting json string to object.
     */
    public VoteCastResult generateVoteCastResult(String tenantId, String electionEventId, String votingCardId,
            String verificationCardId, CastCodeAndComputeResults castCodeComputeResults)
            throws ResourceNotFoundException, IOException {
        VoteCastResult voteCastResult = new VoteCastResult();

        // values
        voteCastResult.setElectionEventId(electionEventId);
        voteCastResult.setVotingCardId(votingCardId);
        voteCastResult.setValid(true);
        voteCastResult.setVoteCastMessage(
            new VoteCastMessage(castCodeComputeResults.getVoteCastCode(), castCodeComputeResults.getSignature()));
        voteCastResult.setVerificationCardId(verificationCardId);

        // vote
        VoteMessage voteMessage = new VoteMessage();

        try {
            VoteAndComputeResults voteAndComputeResults =
                voteRepository.findByTenantIdElectionEventIdVotingCardId(tenantId, electionEventId, votingCardId);

            Vote encryptedVote = voteAndComputeResults.getVote();

            voteMessage.setEncryptedVote(encryptedVote);

            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.VOTE_FOUND).objectId(votingCardId)
                    .user(votingCardId).electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                    .createLogInfo());

            // receipt
            Receipt receipt = voteRepository.getReceiptByVotingCardId(tenantId, electionEventId, votingCardId);
            voteMessage.setReceiptMessage(receipt);

            // token
            String tokenStr = encryptedVote.getAuthenticationToken();
            voteMessage.setAuthenticationToken(ObjectMappers.fromJson(tokenStr, AuthenticationToken.class));
        } catch (ResourceNotFoundException | VoteRepositoryException | ApplicationException e) {
            LOG.error("Error trying to find Vote.", e);
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.VOTE_NOT_FOUND)
                    .objectId(votingCardId).user(votingCardId).electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackIdInstance.getTrackId())
                    .createLogInfo());
        }
        // the vote message
        voteCastResult.setVoteMessage(voteMessage);

        // result
        return voteCastResult;
    }

}
