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

import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.json.Json;
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.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.ErrorCodes;
import com.scytl.products.ov.commons.util.HttpRequestService;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.ei.services.domain.model.ballot.BallotText;
import com.scytl.products.ov.ei.services.domain.model.ballot.BallotTextRepository;

/**
 * Web service for handling text for internationalization of ballot.
 */
@Path("/ballottexts")
@Stateless
public class BallotTextResource {

    private static final String RESOURCE_NAME = "ballottexts";

    // The name of the query parameter tenantId
    private static final String QUERY_PARAMETER_TENANT_ID = "tenantId";

    // The name of the query parameter ballotId
    private static final String QUERY_PARAMETER_BALLOT_ID = "ballotId";

    // The name of the query parameter electionEventId
    private static final String QUERY_PARAMETER_ELECTION_EVENT_ID = "electionEventId";

    private static final String JSON_PARAMETER_BALLOT_TEXTS = "ballotTexts";

    private static final String JSON_PARAMETER_BALLOT_TEXTS_SIGNATURE = "ballotTextsSignature";
    
    private final Gson gson = new Gson();
    
    // The track id instance
    @Inject
    private TrackIdInstance trackIdInstance;
    
    // An instance of the ballot text repository
    @EJB
    private BallotTextRepository ballotTextRepository;
    
    private static final Logger LOG = LoggerFactory.getLogger(BallotTextResource.class);

    @Inject
    private TransactionInfoProvider transactionInfoProvider;

    @Inject
    private HttpRequestService httpRequestService;

    /**
     * Return a ballot text given the tenant, election event and the ballot identifiers.
     *
     * @param tenantId - the tenant identifier.
     * @param electionEventId - the election event identifier.
     * @param ballotId - the ballot identifier.
     * @param trackId - the track id to be used for logging purposes.
     * @param request - the http servlet request.
     * @return Returns the corresponding ballot text for the tenantId, electionEventId and ballotId.
     * @throws ApplicationException if the input parameters are not valid.
     * @throws IOException if there are errors during conversion of ballot to json format.
     * @throws ResourceNotFoundException if the ballot is not found.
     */
    @GET
    @Path("tenant/{tenantId}/electionevent/{electionEventId}/ballot/{ballotId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBallot(@HeaderParam(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackingId,
                              @PathParam(QUERY_PARAMETER_TENANT_ID) String tenantId,
                              @PathParam(QUERY_PARAMETER_ELECTION_EVENT_ID) String electionEventId,
                              @PathParam(QUERY_PARAMETER_BALLOT_ID) String ballotId, @Context HttpServletRequest request)
        throws ApplicationException, IOException, ResourceNotFoundException {
        // set the track id to be logged
        trackIdInstance.setTrackId(trackingId);

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

        LOG.info("Getting ballot text for ballotId: {}, electionEventId: {} and tenantId: {}.", ballotId, electionEventId,
            tenantId);

        // validate parameters
        validateParameters(tenantId, electionEventId, ballotId);

        // search ballot text
        BallotText ballotText =
            ballotTextRepository.findByTenantIdElectionEventIdBallotId(tenantId, electionEventId, ballotId);

        LOG.info("Ballot text with ballotId: {}, electionEventId: {} and tenantId: {} found.", ballotId, electionEventId,
            tenantId);

        // convert to string
        JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
        jsonObjectBuilder.add(JSON_PARAMETER_BALLOT_TEXTS, JsonUtils.getJsonArray(ballotText.getJson()));
        jsonObjectBuilder.add(JSON_PARAMETER_BALLOT_TEXTS_SIGNATURE, JsonUtils.getJsonArray(ballotText.getSignature()));
        String json = gson.toJson(jsonObjectBuilder.build().toString());

        // return the ballot text json
        return Response.ok().entity(json).build();
    }

    // Validate parameters.
    private void validateParameters(String tenantId, String electionEventId, String ballotId) throws ApplicationException {
        if (tenantId == null || tenantId.isEmpty()) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_QUERY_PARAMETER_IS_NULL,
                RESOURCE_NAME, ErrorCodes.MISSING_QUERY_PARAMETER, QUERY_PARAMETER_TENANT_ID);
        }

        if (electionEventId == null || electionEventId.isEmpty()) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_QUERY_PARAMETER_IS_NULL,
                RESOURCE_NAME, ErrorCodes.MISSING_QUERY_PARAMETER, QUERY_PARAMETER_ELECTION_EVENT_ID);
        }

        if (ballotId == null || ballotId.isEmpty()) {
            throw new ApplicationException(ApplicationExceptionMessages.EXCEPTION_MESSAGE_QUERY_PARAMETER_IS_NULL,
                RESOURCE_NAME, ErrorCodes.MISSING_QUERY_PARAMETER, QUERY_PARAMETER_BALLOT_ID);
        }
    }
}
