/*
 * 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 com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.dto.CastCodeAndComputeResults;
import com.scytl.products.ov.commons.dto.ComputeResults;
import com.scytl.products.ov.commons.dto.VoteAndComputeResults;
import com.scytl.products.ov.commons.ui.Constants;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.vw.services.domain.model.confirmation.ConfirmationInformation;
import com.scytl.products.ov.vw.services.domain.model.confirmation.ConfirmationInformationResult;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Path;

/**
 * The Interface for election information client.
 */
public interface ElectionInformationClient {

    /** The Constant PARAMETER_VALUE_TENANT_ID. */
    public static final String PARAMETER_VALUE_TENANT_ID = "tenantId";

    /** The Constant PARAMETER_VALUE_ELECTION_EVENT_ID. */
    public static final String PARAMETER_VALUE_ELECTION_EVENT_ID = "electionEventId";

    /** The Constant PARAMETER_VALUE_BALLOT_ID. */
    public static final String PARAMETER_VALUE_BALLOT_ID = "ballotId";

    /** The Constant PARAMETER_VALUE_BALLOT_BOX_ID. */
    public static final String PARAMETER_VALUE_BALLOT_BOX_ID = "ballotBoxId";

    /** The Constant PARAMETER_VALUE_VOTING_CARD_ID. */
    public static final String PARAMETER_VALUE_VOTING_CARD_ID = "votingCardId";

    /** The Constant PARAMETER_PATH_CAST_CODE. */
    public static final String PARAMETER_PATH_CAST_CODE = "pathCastCode";

    /** The Constant PARAMETER_PATH_CAST_CODE. */
    public static final String PARAMETER_PATH_RECEIPTS = "pathReceipts";

    /** The Constant PARAMETER_PATH_VOTE. */
    public static final String PARAMETER_PATH_VOTE = "pathVote";

    /** The Constant PARAMETER_PATH_BALLOT_BOX. */
    public static final String PARAMETER_PATH_BALLOT_BOX = "pathBallotBox";

    /** The Constant PARAMETER_PATH_BALLOT. */
    public static final String PARAMETER_PATH_BALLOT = "pathBallot";

    /** The Constant PARAMETER_PATH_BALLOT_TEXT. */
    public static final String PARAMETER_PATH_BALLOT_TEXT = "pathBallotText";

    /** The Constant PARAMETER_PATH_CONFIRMATION. */
    public static final String PARAMETER_PATH_CONFIRMATION = "pathConfirmationMessage";

    /** The Constant PARAMETER_PATH_VALIDATION. */
    public static final String PARAMETER_PATH_VALIDATION = "pathValidations";

    /** The Constant PARAMETER_AUTHENTICATION_TOKEN. */
    public static final String PARAMETER_AUTHENTICATION_TOKEN = "authenticationToken";

    /** The Accept Parameter header */
    public static final String PARAMETER_ACCEPT = "Accept";

    /**
     * Gets the ballot box information.
     * 
     * @param acceptType
     *            the content type which is accepted
     * @param trackId
     *            the track id
     * @param pathBallotBox
     *            the path ballot box
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param ballotBoxId
     *            the ballot box id
     * @return the ballot box information
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @GET("{pathBallotBox}/tenant/{tenantId}/electionevent/{electionEventId}/ballotbox/{ballotBoxId}")
    Call<String> getBallotBoxInformation(@Header(PARAMETER_ACCEPT) String acceptType,
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_BALLOT_BOX) String pathBallotBox, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_BALLOT_BOX_ID) String ballotBoxId) throws ResourceNotFoundException;

    /**
     * Gets the ballot.
     *
     * @param trackId
     *            the track id
     * @param pathBallot
     *            the path ballot
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param ballotId
     *            the ballot id
     * @return the ballot
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @GET("{pathBallot}/tenant/{tenantId}/electionevent/{electionEventId}/ballot/{ballotId}")
    Call<String> getBallot(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_BALLOT) String pathBallot, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_BALLOT_ID) String ballotId) throws ResourceNotFoundException;

    /**
     * Find ballot text by tenant id election event id ballot id.
     *
     * @param trackId
     *            the track id
     * @param pathBallotText
     *            the path ballot text
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param ballotId
     *            the ballot id
     * @return the string
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @GET("{pathBallotText}/tenant/{tenantId}/electionevent/{electionEventId}/ballot/{ballotId}")
    Call<String> findBallotTextByTenantIdElectionEventIdBallotId(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_BALLOT_TEXT) String pathBallotText, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_BALLOT_ID) String ballotId) throws ResourceNotFoundException;

    /**
     * Validate confirmation message.
     *
     * @param trackId
     *            the track id
     * @param pathConfirmationMessage
     *            the path confirmation message
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @param confirmationInformation
     *            the confirmation information
     * @param token
     *            the token
     * @return the confirmation information result
     */
    @POST("{pathConfirmationMessage}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}")
    Call<ConfirmationInformationResult> validateConfirmationMessage(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_CONFIRMATION) String pathConfirmationMessage,
            @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId,
            @Body ConfirmationInformation confirmationInformation,
            @Header(PARAMETER_AUTHENTICATION_TOKEN) String token);

    /**
     * Validate vote.
     *
     * @param tenantId
     *            - the tenant id
     * @param electionEventId
     *            - the election event id
     * @param trackId
     *            the track id
     * @param pathValidations
     *            the path validations
     * @param vote
     *            the vote
     * @return the validation result
     */
    @POST("{pathValidations}/tenant/{tenantId}/electionevent/{electionEventId}")
    Call<com.scytl.products.ov.commons.validation.ValidationResult> validateVote(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_VALIDATION) String pathValidations, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId, @Body Vote vote);

    /**
     * The endpoint to validate if an election is in dates.
     *
     * @param requestId
     *            - the request id for logging purposes.
     * @param pathBallotBoxes
     *            the path materials
     * @param tenantId
     *            - the tenant id
     * @param electionEventId
     *            - the election event id
     * @param ballotBoxId
     *            - the ballot box id
     * @return the validation error for a given tenant, election event and
     *         ballot box ids.
     * @throws ResourceNotFoundException
     *             if the rest operation fails.
     */
    @POST("{pathValidations}/tenant/{tenantId}/electionevent/{electionEventId}/ballotbox/{ballotBoxId}")
    Call<ValidationResult> validateElectionInDates(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String requestId,
            @Path(PARAMETER_PATH_VALIDATION) String pathBallotBoxes, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_BALLOT_BOX_ID) String ballotBoxId) throws ResourceNotFoundException;

    /**
     * Save vote.
     *
     * @param tenantId
     *            - the tenant id
     * @param electionEventId
     *            - the election event id
     * @param trackId
     *            the track id
     * @param pathVote
     *            the path vote
     * @param vote
     *            the vote with computation proofs and signature
     * @param token
     *            the token
     * @return the receipt
     */
    @POST("{pathVote}/tenant/{tenantId}/electionevent/{electionEventId}")
    Call<com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt> saveVote(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId, @Path(PARAMETER_PATH_VOTE) String pathVote,
            @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId, @Body VoteAndComputeResults vote,
            @Header(PARAMETER_AUTHENTICATION_TOKEN) String token);

    /**
     * Gets the vote.
     *
     * @param trackId
     *            the track id
     * @param pathVote
     *            the path vote
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @return the vote
     * @throws ResourceNotFoundException
     *             the resource not found exception
     */
    @GET("{pathVote}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}")
    Call<VoteAndComputeResults> getVote(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_VOTE) String pathVote, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId) throws ResourceNotFoundException;

    /**
     * Store cast code.
     *
     * @param trackId
     *            the track id
     * @param castCode
     *            the cast code
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @param voteCastMessage
     *            the vote cast message
     * @return the validation result
     */
    @POST("{pathCastCode}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}")
    Call<ValidationResult> storeCastCode(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_CAST_CODE) String castCode, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId, @Body CastCodeAndComputeResults voteCastMessage);

    /**
     * Get the cast code.
     *
     * @param trackId
     *            the track id
     * @param castCode
     *            the cast code
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @return the cast code
     */
    @GET("{pathCastCode}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}")
    Call<CastCodeAndComputeResults> getVoteCastCode(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_CAST_CODE) String castCode, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId);

    /**
     * Get the cast code.
     *
     * @param trackId
     *            the track id
     * @param pathReceipts
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @return the cast code
     */
    @GET("{pathReceipts}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}")
    Call<com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt> getReceipt(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_RECEIPTS) String pathReceipts, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId);

    /**
     * Check if a VoteCastCode exists
     *
     * @param trackId
     *            the track id
     * @param castCode
     *            the cast code
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @return the cast code
     */
    @GET("{pathCastCode}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}/available")
    Call<ResponseBody> checkVoteCastCode(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_CAST_CODE) String castCode, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId);

    /**
     * Check if a vote exists.
     *
     * @param trackId
     *            the track id
     * @param pathVote
     *            the path vote
     * @param tenantId
     *            the tenant id
     * @param electionEventId
     *            the election event id
     * @param votingCardId
     *            the voting card id
     * @return votes exists (200 OK), does not exist (404 Not Found)
     */
    @GET("{pathVote}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}/available")
    Call<ResponseBody> checkVote(@Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_VOTE) String pathVote, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId);

    @GET("{pathVote}/tenant/{tenantId}/electionevent/{electionEventId}/votingcard/{votingCardId}/partialdecryption")
    Call<ComputeResults> getPartialDecryptionResultsIfAny(
            @Header(Constants.PARAMETER_HEADER_X_REQUEST_ID) String trackId,
            @Path(PARAMETER_PATH_VOTE) String pathPartialDecryption, @Path(PARAMETER_VALUE_TENANT_ID) String tenantId,
            @Path(PARAMETER_VALUE_ELECTION_EVENT_ID) String electionEventId,
            @Path(PARAMETER_VALUE_VOTING_CARD_ID) String votingCardId);
}
