/*
 * 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.infrastructure.remote;

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

import javax.decorator.Decorator;
import javax.decorator.Delegate;
import javax.inject.Inject;
import java.io.IOException;

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.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitException;
import com.scytl.products.ov.commons.logging.I18nLoggerMessages;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.vw.infrastructure.log.SecureLoggerInformation;
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.AuthenticationTokenMessage;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationTokenRepository;
import com.scytl.products.ov.vw.services.domain.model.authentication.ChallengeInformation;

/**
 * Decorator of the authentication token repository.
 */
@Decorator
public class AuthenticationTokenRepositoryDecorator implements AuthenticationTokenRepository {
    @Inject
    @Delegate
    private AuthenticationTokenRepository authenticationTokenRepository;

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

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

    @Inject
    private TrackIdInstance trackId;

    @Inject
    private SecureLoggingWriter secureLoggerWriter;

    @Inject
    private SecureLoggerInformation secureLoggerInformation;

    /**
     * @see com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationTokenRepository#getAuthenticationToken(java.lang.String,
     *      java.lang.String, java.lang.String,
     *      com.scytl.products.ov.vw.services.domain.model.authentication.ChallengeInformation)
     */
    @Override
    public AuthenticationTokenMessage getAuthenticationToken(String tenantId, String electionEventId,
            String credentialId, ChallengeInformation challengeInformation) throws ResourceNotFoundException, ApplicationException {
        LOG.info(I18N.getMessage("AuthenticationInformationRepoImpl.getAuthToken"), tenantId, electionEventId,
            credentialId);
        try {
            AuthenticationTokenMessage authenticationToken = authenticationTokenRepository
                .getAuthenticationToken(tenantId, electionEventId, credentialId, challengeInformation);
            LOG.info(I18N.getMessage("AuthenticationInformationRepoImpl.getAuthToken.found"),
                authenticationToken.getAuthenticationToken() != null, tenantId, electionEventId, credentialId);

            secureLoggerWriter.log(Level.INFO,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.AUTH_TOKEN_GENERATED)
                    .electionEvent(electionEventId).objectId(secureLoggerInformation.getAuthenticationTokenHash())
                    .user(credentialId).additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .createLogInfo());
            return authenticationToken;
        } catch ( ResourceNotFoundException e) {
            LOG.error(I18N.getMessage("AuthenticationInformationRepoImpl.getAuthToken.notFound"), tenantId,
                electionEventId, credentialId);
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.AUTH_TOKEN_NOT_GENERATED)
                    .electionEvent(electionEventId).objectId(secureLoggerInformation.getAuthenticationTokenHash())
                    .user(credentialId).additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC,
                        "Authentication token not generated: " + ExceptionUtils.getRootCauseMessage(e))
                    .createLogInfo());
            if (e instanceof RetrofitException) {
            	RetrofitException error = (RetrofitException)e;
                if( error.getHttpCode() == 404) {
                    throw new ResourceNotFoundException(error.getMessage());
                } else {
                    throw new ApplicationException(e.getMessage());
                }
            } else {
                throw e;
            }

        }
    }

    /**
     * @see com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationTokenRepository#validateAuthenticationToken(java.lang.String,
     *      java.lang.String, java.lang.String,
     *      com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationToken)
     */
    @Override
    public ValidationResult validateAuthenticationToken(String tenantId, String electionEventId, String votingCardId,
            String authenticationToken) throws IOException, ResourceNotFoundException, ApplicationException {
        LOG.info(I18N.getMessage("AuthenticationInformationRepoImpl.validateAuthToken"), tenantId, electionEventId,
            votingCardId);
        try {
            ValidationResult validationResult = authenticationTokenRepository.validateAuthenticationToken(tenantId,
                electionEventId, votingCardId, authenticationToken);
            if (validationResult.isResult()) {
                secureLoggerWriter.log(Level.INFO,
                    new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.AUTH_TOKEN_VALIDATION_OK)
                        .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                        .electionEvent(electionEventId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                        .createLogInfo());
            } else {
                secureLoggerWriter.log(Level.ERROR,
                    new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.AUTH_TOKEN_VALIDATION_ERROR)
                        .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                        .electionEvent(electionEventId)
                        .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_AUTH_TOKEN_ID,
                            secureLoggerInformation.getAuthenticationTokenId())
                        .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC, "Auth Token validation fails")
                        .createLogInfo());
            }
            return validationResult;
        } catch (ResourceNotFoundException e) {
            LOG.error(I18N.getMessage("AuthenticationInformationRepoImpl.getAuthToken.notFound"), tenantId,
                electionEventId, votingCardId);
            secureLoggerWriter.log(Level.ERROR,
                new LogContent.LogContentBuilder().logEvent(VotingWorkflowLogEvents.AUTH_TOKEN_VALIDATION_ERROR)
                    .objectId(secureLoggerInformation.getAuthenticationTokenHash()).user(votingCardId)
                    .electionEvent(electionEventId)
                    .additionalInfo(VotingWorkflowLogConstants.INFO_TRACK_ID, trackId.getTrackId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_AUTH_TOKEN_ID,
                        secureLoggerInformation.getAuthenticationTokenId())
                    .additionalInfo(VotingWorkflowLogConstants.INFO_ERR_DESC,
                        "Authentication token validation error: " + ExceptionUtils.getRootCauseMessage(e))
                    .createLogInfo());
            if (e instanceof RetrofitException) {
            	RetrofitException error = (RetrofitException)e;
                if( error.getHttpCode() == 404) {
                    throw new ResourceNotFoundException(error.getMessage());
                } else {
                    throw new ApplicationException(e.getMessage());
                }
            } else {
                throw e;
            }
        }
    }
}
