/*
 * 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.au.services.domain.model.authentication;

import java.io.IOException;
import java.security.PrivateKey;

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

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.ov.au.services.infrastructure.persistence.AuTenantSystemKeys;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.utils.PasswordEncrypter;
import com.scytl.products.ov.commons.cache.Cache;
import com.scytl.products.ov.commons.crypto.PasswordForObjectRepository;
import com.scytl.products.ov.commons.util.JsonUtils;

/**
 * Implementation of the repository with jpa
 */
public class AuthenticationPasswordForObjectRepository
        implements PasswordForObjectRepository {

    // The encryption keystore password name in the contents json.
	private static final String AUTHENTICATION_TOKEN_SIGNER_PW = "authenticationTokenSignerPassword";
	
	private static final String KEY_SEPERATOR = "-";
	
    @EJB
    AuthenticationContentRepository repository;

    @EJB
    private AuTenantSystemKeys auTenantSystemKeys;

    @Inject
    private AsymmetricServiceAPI asymmetricService;

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

    

    /**
     * Retrieves the password for one keystore given a tenant identifier, the
     * electionEventIdentifier and the verification card set id.
     *
     * @param tenantId
     *            the tenant identifier.
     * @param electionEventId
     *            the election event identifier.
     * @param id
     *            - It does not apply
     * @param alias
     *            - the alias used for getting the password
     * @return the keystore data represented as a string.
     * @throws ResourceNotFoundException
     *             if the keystore data can not be found.
     * @see com.scytl.products.ov.commons.crypto.KeystoreForObjectRepository#getJsonByTenantEEIDObjectId(java.lang.String,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public String getByTenantEEIDObjectIdAlias(final String tenantId,
            final String electionEventId, final String id,
            final String alias) throws ResourceNotFoundException {

        // Watch out: alias is not being used. Is it really needed? It was
        // introduced before objectId.

        String cacheKey = constructCacheKey(tenantId, electionEventId);

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

        // recover from db
        AuthenticationContentEntity authenticationContent = repository
            .findByTenantIdElectionEventId(tenantId, electionEventId);

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

        String passwordFromDB = object.getString(AUTHENTICATION_TOKEN_SIGNER_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 auth token signer keystore password",
                e);
        }

        passwordCache.put(cacheKey, decryptedString);

        return decryptedString;
    }

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

        PasswordEncrypter passwordEncrypter =
            new PasswordEncrypter(asymmetricService);

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

        return passwordEncrypter.decryptPassword(passwordFromDB, privateKey);
    }

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

        return tenantId + KEY_SEPERATOR + electionEventId;
    }
}
