/*
 * 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.security.PrivateKey;

import javax.ejb.EJB;
import javax.inject.Inject;
import javax.json.JsonObject;

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

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.crypto.PasswordForObjectRepository;
import com.scytl.products.ov.commons.logging.I18nLoggerMessages;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxContent;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxContentRepository;
import com.scytl.products.ov.ei.services.domain.model.tenant.EiTenantSystemKeys;
import com.scytl.products.ov.commons.beans.utils.PasswordEncrypter;
import com.scytl.products.ov.commons.cache.Cache;

/**
 * Recovers the private key for a ballot box keystore.
 */
public class BallotBoxPasswordRepository implements PasswordForObjectRepository {

	private static final Logger LOG = LoggerFactory.getLogger("std");

    private static final I18nLoggerMessages I18N = I18nLoggerMessages.getInstance();

    // The Constant KEYSTORE_PASSWORD.
    private static final String KEYSTORE_PW = "passwordKeystore";

    // The ballot box content repository.
    @Inject
    private BallotBoxContentRepository ballotBoxContentRepository;

    @EJB
    private EiTenantSystemKeys eiTenantSystemKeys;

    @Inject
    private AsymmetricServiceAPI asymmetricService;

    @EJB(beanName="BallotBoxSignerKeystorePasswordCache")
    private Cache<String, String> passwordCache;

    private static final String KEY_SEPERATOR = "-";

    @Override
    public String getByTenantEEIDObjectIdAlias(final String tenantId, final String electionEventId,
            final String ballotBoxId, final String alias) throws ResourceNotFoundException {
        LOG.info(I18N.getMessage("BallotBoxPasswordRepository.getByTenantEEIDObjectIdAlias.recoveringKeystorePassword"),
            tenantId, electionEventId, ballotBoxId);

        String cacheKey = constructCacheKey(tenantId, electionEventId, ballotBoxId);

        String cachedPassword = passwordCache.get(cacheKey);
        if ((cachedPassword != null) && (!"".equals(cachedPassword))) {
        	return cachedPassword;
        }

        // recover from db
        BallotBoxContent ballotBoxContent =
            ballotBoxContentRepository.findByTenantIdElectionEventIdBallotBoxId(tenantId, electionEventId, ballotBoxId);

        // convert to json object
        JsonObject object = JsonUtils.getJsonObject(ballotBoxContent.getJson());

        LOG.info(I18N.getMessage("BallotBoxPasswordRepository.getByTenantEEIDObjectIdAlias.keystorePasswordFound"),
            tenantId, electionEventId, ballotBoxId);

        String passwordFromDB = object.getString(KEYSTORE_PW);

        String decryptedString;
        try {
            decryptedString = decryptedPassword(tenantId, passwordFromDB);
        } catch (GeneralCryptoLibException | IOException e) {
            throw new ResourceNotFoundException(
                "Error while trying to recover tenant system password to decrypt the ballot box password to decrypt the ballot box signer keystore password",
                e);
        }

        passwordCache.put(cacheKey, decryptedString);

        return decryptedString;
    }

    private String constructCacheKey(final String tenantId, final String electionEventId, final String ballotBoxId) {

        return tenantId + KEY_SEPERATOR + electionEventId + KEY_SEPERATOR + ballotBoxId;
    }

    private String decryptedPassword(final String tenantId, final String passwordFromDB)
            throws GeneralCryptoLibException, IOException {

        PasswordEncrypter passwordEncrypter = new PasswordEncrypter(asymmetricService);

        PrivateKey privateKey = eiTenantSystemKeys.getTenantPrivateKeys(tenantId).get(0);

        return passwordEncrypter.decryptPassword(passwordFromDB, privateKey);
    }
}
