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

import java.io.IOException;
import java.util.List;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt;
import com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
import com.scytl.products.ov.commons.dto.ComputeResults;
import com.scytl.products.ov.commons.dto.VoteAndComputeResults;
import com.scytl.products.ov.commons.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.commons.util.ZipUtils;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.AdditionalData;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBox;

public class BallotBoxFactory {

    private static final String VOTE = "vote";

    private static final String RECEIPT = "receipt";

    private static final String AUTHENTICATION_TOKEN = "authenticationToken";

    private static final String ADDITIONAL_DATA = "additionalData";

    public BallotBox from(Vote vote, ComputeResults computationResults, Receipt receipt, String authenticationToken,
            List<AdditionalData> additionalData) {
        BallotBox ballotBox = informationFrom(vote);
        final String voteAsJSON = obtainVote(vote, receipt, authenticationToken, additionalData);
        ballotBox.setVote(voteAsJSON);

        try {
            ballotBox.setComputationResults(ZipUtils.zipText(ObjectMappers.toJson(computationResults)));
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException(e);
        }

        return ballotBox;
    }

    private BallotBox informationFrom(Vote vote) {
        BallotBox ballotBox = new BallotBox();
        ballotBox.setTenantId(vote.getTenantId());
        ballotBox.setElectionEventId(vote.getElectionEventId());
        ballotBox.setVotingCardId(vote.getVotingCardId());
        ballotBox.setBallotId(vote.getBallotId());
        ballotBox.setBallotBoxId(vote.getBallotBoxId());
        return ballotBox;
    }

    private String obtainVote(Vote vote, Receipt receipt, String authenticationToken,
            List<AdditionalData> additionalData) {
        JsonObjectBuilder jsonVoteBuilder = Json.createObjectBuilder();
        try {
            JsonObject voteJson = JsonUtils.getJsonObject(ObjectMappers.toJson(vote));
            JsonObject receiptJson = JsonUtils.getJsonObject(ObjectMappers.toJson(receipt));
            JsonObject authenticationTokenJson = JsonUtils.getJsonObject(authenticationToken);
            jsonVoteBuilder.add(VOTE, voteJson).add(RECEIPT, receiptJson).add(AUTHENTICATION_TOKEN,
                authenticationTokenJson);
            if (null != additionalData && !additionalData.isEmpty()) {
                JsonArray additionalDataJson = JsonUtils.getJsonArray(ObjectMappers.toJson(additionalData));
                jsonVoteBuilder.add(ADDITIONAL_DATA, additionalDataJson);
            }
            return jsonVoteBuilder.build().toString();
        } catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
    }

    public VoteAndComputeResults to(BallotBox ballotBox) throws JsonParseException, JsonMappingException, IOException {
        VoteAndComputeResults voteAndComputeResults = new VoteAndComputeResults();
        ComputeResults computeResults =
            ObjectMappers.fromJson(ZipUtils.unzip(ballotBox.getComputationResults()), ComputeResults.class);
        voteAndComputeResults.setComputeResults(computeResults);

        final String voteAsJSON = ballotBox.getVote();
        Vote vote = restoreVote(voteAsJSON);
        voteAndComputeResults.setVote(vote);

        return voteAndComputeResults;
    }

    private Vote restoreVote(String jsonWithVote) throws JsonParseException, JsonMappingException, IOException {

        JsonObject jsonObjectWithVote = JsonUtils.getJsonObject(jsonWithVote);
        JsonObject voteJson = jsonObjectWithVote.getJsonObject(VOTE);
        return ObjectMappers.fromJson(voteJson.toString(), Vote.class);
    }
}
