/*
 * 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.ag.ui.ws.rs.operation.voting;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitConsumer;
import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitException;
import retrofit2.http.Body;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.Reader;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.ov.ag.model.EncryptedSVK;
import com.scytl.products.ov.ag.model.ExtendedAuthResponse;
import com.scytl.products.ov.ag.model.ExtendedAuthentication;
import com.scytl.products.ov.ag.model.NumberOfRemainingAttempts;
import com.scytl.products.ov.ag.services.infrastructure.remote.voting.ExtendedAuthenticationVotingClient;
import com.scytl.products.ov.ag.ui.ws.rs.RestApplication;
import com.scytl.products.ov.ag.ui.ws.rs.proxy.XForwardedForFactory;
import com.scytl.products.ov.ag.ui.ws.rs.proxy.XForwardedForFactoryImpl;
import com.scytl.products.ov.commons.beans.domain.model.authentication.ExtendedAuthenticationUpdateRequest;
import com.scytl.products.ov.commons.tracking.TrackIdGenerator;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.util.PropertiesFileReader;

/**
 * The end point for the Extended Authentication feature.
 */
@Stateless(name = "ag-ExtAuthResource")
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@Path(ExtendedAuthenticationResource.RESOURCE_PATH)
public class ExtendedAuthenticationResource {

    static final String RESOURCE_PATH = RestApplication.API_OV_VOTING_BASEURI_EXTENDED_AUTH + "/" + RestApplication.PARAMETER_EXTENDED_AUTH_PATH;

    private static final PropertiesFileReader PROPERTIES = PropertiesFileReader.getInstance();

    static final String EXT_AUTH_PATH = PROPERTIES.getPropertyValue("EXTENDED_AUTHENTICATION_PATH");

    private final XForwardedForFactory xForwardedForFactory = XForwardedForFactoryImpl.getInstance();

    private ExtendedAuthenticationVotingClient extendedAuthClient;

    /**
     * The length in characters of the random generated string.
     */
    public static final int LENGTH_IN_CHARS = 16;

    private TrackIdGenerator trackIdGenerator;
    
    private static final Logger LOG = LoggerFactory.getLogger(ExtendedAuthenticationResource.class);
    
	@Inject
	ExtendedAuthenticationResource(ExtendedAuthenticationVotingClient extendedAuthenticationVotingClient,
			TrackIdGenerator trackIdGenerator) {
		this.extendedAuthClient = extendedAuthenticationVotingClient;
		this.trackIdGenerator = trackIdGenerator;
	}

    @POST
    @Path("")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getEncryptedStartVotingKey(
            @PathParam(RestApplication.PARAMETER_VALUE_VERSION) final String version,
            @PathParam(RestApplication.PARAMETER_VALUE_TENANT_ID) final String tenantId,
            @PathParam(RestApplication.PARAMETER_VALUE_ELECTION_EVENT_ID) final String electionEventId,
            @NotNull final Reader extendedAuthReader, @Context final HttpServletRequest request)
            throws IOException {
        String xForwardedFor = xForwardedForFactory.newXForwardedFor(request);
        String trackingId = trackIdGenerator.generate();

        ExtendedAuthResponse extendedAuthResponse = null;
        Response.ResponseBuilder builder;
        try {
            final ExtendedAuthentication extendedAuthentication =
                    ObjectMappers.fromJson(extendedAuthReader, ExtendedAuthentication.class);
            extendedAuthResponse =
                    RetrofitConsumer.processResponse(extendedAuthClient.getEncryptedStartVotingKey(EXT_AUTH_PATH, tenantId, electionEventId, xForwardedFor,
                            trackingId, extendedAuthentication));

            Response.Status status = Response.Status.valueOf(extendedAuthResponse.getResponseCode());

            switch (status) {
                case OK:
                    builder = Response.ok().entity(new EncryptedSVK(extendedAuthResponse.getEncryptedSVK()));
                    break;
                case UNAUTHORIZED:
                    builder =
                            Response.ok().entity(
                                    new NumberOfRemainingAttempts(extendedAuthResponse.getNumberOfRemainingAttempts()));
                    break;
                default:
                    builder = Response.status(status);
                    break;
            }

            return builder.build();

        } catch (RetrofitException e) {
            LOG.error("Error in extended authentication", e);
            return Response.status(e.getHttpCode()).build();
        }
    }

    @PUT
    @Path("")
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateExtendedAuthData(
            @PathParam(RestApplication.PARAMETER_VALUE_VERSION) final String version, 
            @PathParam(RestApplication.PARAMETER_VALUE_TENANT_ID) final String tenantId, 
            @PathParam(RestApplication.PARAMETER_VALUE_ELECTION_EVENT_ID) final String electionEventId,
            @HeaderParam(RestApplication.PARAMETER_AUTHENTICATION_TOKEN) final String authenticationToken,
            @NotNull @Body final Reader extendedAuthUpdateReader, @Context final HttpServletRequest request)
            throws IOException, GeneralCryptoLibException {
        String xForwardedFor = xForwardedForFactory.newXForwardedFor(request);
        String trackingId = trackIdGenerator.generate();

        ExtendedAuthResponse extendedAuthResponse = null;

        try {
            final ExtendedAuthenticationUpdateRequest extendedAuthenticationUpdate =
                    ObjectMappers.fromJson(extendedAuthUpdateReader, ExtendedAuthenticationUpdateRequest.class);
            extendedAuthResponse =
                    RetrofitConsumer.processResponse(extendedAuthClient.updateExtendedAuthData(EXT_AUTH_PATH, tenantId, electionEventId,
                            authenticationToken, xForwardedFor, trackingId, extendedAuthenticationUpdate));

            Response.Status status = Response.Status.valueOf(extendedAuthResponse.getResponseCode());

            return Response.status(status).build();

        } catch (RetrofitException e) {
            LOG.error("Error in extended authentication", e);
            return Response.status(e.getHttpCode()).build();
        }
    }
}
