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

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
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 com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationExceptionMessages;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.ui.Constants;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.util.HttpRequestService;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.vw.services.domain.model.authentication.CredentialInformation;
import com.scytl.products.ov.vw.services.domain.model.authentication.CredentialInformationRepository;

/**
 * The end point for authentication information resource.
 */
@Path("/informations")
@Stateless(name = "vw-CredentialInformationResource")
public class CredentialInformationResource {

    // The name of the parameter value tenant id.
    private static final String PARAMETER_VALUE_TENANT_ID = "tenantId";

    // The name of the parameter value credential id.
    private static final String PARAMETER_CREDENTIAL_ID = "credentialId";

    // The name of the parameter value election event id.
    private static final String PARAMETER_VALUE_ELECTION_EVENT_ID = "electionEventId";

    private static final String CERTIFICATES = "certificates";

    private static final String CREDENTIAL_DATA = "credentialData";

    private static final String SERVER_CHALLANGE_MESSAGE = "serverChallengeMessage";

    private static final String CERTS_SIGNATURE = "certificatesSignature";

    @EJB
    private CredentialInformationRepository credentialInformationRepository;

    @Inject
    private TrackIdInstance trackIdInstance;

    @Inject
    private TransactionInfoProvider transactionInfoProvider;

    @Inject
    private HttpRequestService httpRequestService;

    /**
     * Reads authentication information requested for the tenant identified by
     * tenantId, election event and voting card.
     *
     * @param tenantId
     *            - the identifier of the tenant.
     * @param electionEventId
     *            - the identifier of the election event.
     * @param credentialId
     *            - the identifier of the credential.
     * @return If the operation is successfully performed, returns a response
     *         with HTTP status code 200 and the authentication information in
     *         json format.
     * @throws ApplicationException
     *             if one of the input parameters is not valid.
     * @throws ResourceNotFoundException
     *             if there is no voter material found.
     * @throws GeneralCryptoLibException
     *             if length is out of the range for this generator during
     *             creation of challenge in AuthenticationInformation or in
     *             requestId generation.
     */
    @GET
    @Path("/tenant/{tenantId}/electionevent/{electionEventId}/credential/{credentialId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAuthenticationInformation(@HeaderParam(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackingId,
                                                 @PathParam(PARAMETER_VALUE_TENANT_ID) String tenantId,
                                                 @PathParam(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
                                                 @PathParam(PARAMETER_CREDENTIAL_ID) String credentialId,
                                                 @Context HttpServletRequest request)
        throws ApplicationException, ResourceNotFoundException, GeneralCryptoLibException, IOException {

        // set the track id to be logged
        trackIdInstance.setTrackId(trackingId);

        // transaction id generation
        transactionInfoProvider.generate(tenantId, httpRequestService.getIpClientAddress(request),
            httpRequestService.getIpServer(request));

        // in case something from the input is not valid, it throws an exception
        validateInput(tenantId, electionEventId, credentialId);

        CredentialInformation credentialInformation = credentialInformationRepository
            .findByTenantElectionEventCredential(tenantId, electionEventId, credentialId);

        // convert from json to object response
        JsonObjectBuilder credentialInfoJson = Json.createObjectBuilder();

        JsonObject certificatesJson = JsonUtils.getJsonObject(credentialInformation.getCertificates());
        JsonObject credentialDataJson =
            JsonUtils.getJsonObject(ObjectMappers.toJson(credentialInformation.getCredentialData()));
        JsonObject serverChallengeMessageJson =
            JsonUtils.getJsonObject(ObjectMappers.toJson(credentialInformation.getServerChallengeMessage()));
        credentialInfoJson.add(CERTIFICATES, certificatesJson).add(CREDENTIAL_DATA, credentialDataJson)
            .add(SERVER_CHALLANGE_MESSAGE, serverChallengeMessageJson);
        credentialInfoJson.add(CERTS_SIGNATURE, credentialInformation.getCertificatesSignature());

        JsonObject result = credentialInfoJson.build();

        // find authentication information
        return Response.ok().entity(result.toString()).build();

    }

    // Does a basic validation of the input. In case something is wrong, just
    // throws an exception.
    private void validateInput(String tenantId, String electionEventId, String credentialId)
        throws ApplicationException {
        if (tenantId == null || "".equals(tenantId)) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_TENANT_ID_IS_NULL);
        }
        if (electionEventId == null || "".equals(electionEventId)) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_ELECTION_EVENT_ID_IS_NULL);
        }
        if (credentialId == null || "".equals(credentialId)) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_CREDENTIAL_ID_IS_NULL);
        }
    }

}
