/*
 * 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.commons.tenant;

import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.certificates.bean.X509CertificateType;
import com.scytl.cryptolib.scytl.keystore.cryptoapi.CryptoAPIScytlKeyStore;
import com.scytl.products.ov.commons.beans.domain.model.tenant.TenantActivationData;
import com.scytl.products.ov.commons.beans.domain.model.tenant.TenantSystemKeys;
import com.scytl.products.ov.commons.beans.utils.KeyStoreLoader;
import com.scytl.products.ov.commons.domain.model.tenant.TenantKeystoreEntity;
import com.scytl.products.ov.commons.domain.model.tenant.TenantKeystoreRepository;
import java.security.cert.CertificateException;
import java.util.Map;

import mockit.Expectations;
import mockit.Mocked;
import mockit.NonStrictExpectations;

public class TenantActivatorTest {

    private TenantActivator _target;

    @BeforeClass
    public static void setUp() {
        System.setProperty("tenantpasswordsdirectory", "tenantpasswordsdirectory");
    }

    @Test
    public void testActivateUsingReceivedKeystore(@Mocked final TenantKeystoreRepository tenantKeystoreRepo,
            @Mocked final TenantSystemKeys tenantSysKeys, @Mocked final TenantActivatorTools tenantActivatorTools,
            @Mocked final KeyStoreLoader keyStoreLoader, @Mocked final CryptoAPIScytlKeyStore cryptoAPIScytlKeyStore,
            @Mocked Map<String, PrivateKey> privateKeys, @Mocked Map<String, X509Certificate[]> certificateChains)
            throws IOException, GeneralCryptoLibException, CertificateException {

        String tenantID = "tenantID";
        String serviceName = "AU";
        String passwordAsString = "RBW6WD4IPTA73VT4KASLILIIFJ";
        char[] passwordAsCharArray = passwordAsString.toCharArray();
        String keystoreBase64 =
            "[encoded data, 8356 characters]";

        _target = new TenantActivator(tenantKeystoreRepo, tenantSysKeys, serviceName);

        new Expectations() {
            {
                tenantActivatorTools.getPasswordFromFile((String) any, (String) any, (String) any);
                times = 1;
                result = passwordAsCharArray;

                KeyStoreLoader.loadKeyStoreFromStream((InputStream) any, passwordAsCharArray);
                times = 1;
                result = cryptoAPIScytlKeyStore;

                tenantActivatorTools.getPrivateKeys(cryptoAPIScytlKeyStore, passwordAsCharArray);
                times = 1;
                result = privateKeys;

                tenantSysKeys.setInitialized(tenantID, privateKeys);
                times = 1;

                tenantActivatorTools.getCertificateChains(cryptoAPIScytlKeyStore);
                times = 1;
                result = certificateChains;

                tenantSysKeys.addCertificateChains(tenantID, certificateChains);
                times = 1;
            }
        };

        _target.activateUsingReceivedKeystore(tenantID, keystoreBase64);
    }

    @Test
    public void testActivateTenantsFromDbAndFiles(@Mocked final TenantKeystoreRepository tenantKeystoreRepo,
            @Mocked final TenantSystemKeys tenantSysKeys, @Mocked final TenantActivatorTools tenantActivatorTools)
            throws IOException {

        String serviceName = "AU";

        List<TenantActivationData> tenantDataList = new ArrayList<>();
        TenantActivationData tenantActivationData1 = new TenantActivationData();
        tenantActivationData1.setTenantID("tenantID1");
        TenantActivationData tenantActivationData2 = new TenantActivationData();
        tenantActivationData2.setTenantID("tenantID2");
        tenantDataList.add(tenantActivationData1);
        tenantDataList.add(tenantActivationData2);

        _target = new TenantActivator(tenantKeystoreRepo, tenantSysKeys, serviceName);

        new Expectations() {
            {

                tenantActivatorTools.getListTenantsFromPasswordFiles((String) any, serviceName);
                result = tenantDataList;
                times = 1;

                tenantKeystoreRepo.checkIfKeystoreExists("tenantID1", X509CertificateType.ENCRYPT.name());
                result = false;
                times = 1;

                tenantKeystoreRepo.checkIfKeystoreExists("tenantID2", X509CertificateType.ENCRYPT.name());
                result = false;
                times = 1;

                tenantActivatorTools.attemptToDeletePasswordsFiles((String) any, serviceName, (String) any);
                times = 2;
            }
        };

        _target.activateTenantsFromDbAndFiles();
    }

    @Test
    public void testActivateFromDB(@Mocked final TenantActivationData tenantActivationData,
            @Mocked final TenantKeystoreRepository tenantKeystoreRepo, @Mocked final TenantSystemKeys tenantSysKeys,
            @Mocked final TenantActivatorTools tenantActivatorTools, @Mocked final KeyStoreLoader keyStoreLoader,
            @Mocked final CryptoAPIScytlKeyStore cryptoAPIScytlKeyStore, @Mocked Map<String, PrivateKey> privateKeys,
            @Mocked final TenantKeystoreEntity tenantKeystoreEntity,
            @Mocked Map<String, X509Certificate[]> certificateChains)
            throws GeneralCryptoLibException, CertificateException {

        String tenantID = "tenantID";
        String serviceName = "AU";
        String passwordAsString = "RBW6WD4IPTA73VT4KASLILIIFJ";
        char[] passwordAsCharArray = passwordAsString.toCharArray();
        String keystoreBase64 =
            "[encoded data, 8356 characters]";

        TenantActivationData tenantActivationData1 = new TenantActivationData();
        tenantActivationData1.setTenantID("tenantID1");
        tenantActivationData1.setSystemKeystorePassword("password");

        _target = new TenantActivator(tenantKeystoreRepo, tenantSysKeys, serviceName);

        new NonStrictExpectations() {
            {

                tenantActivationData.getTenantID();
                times = 1;
                result = tenantID;

                tenantActivationData.getSystemKeystorePassword();
                times = 1;
                result = passwordAsString;

                tenantKeystoreEntity.getKeystoreContent();
                times = 1;
                result = keystoreBase64;

                KeyStoreLoader.loadKeyStoreFromStream((InputStream) any, passwordAsCharArray);
                times = 1;
                result = cryptoAPIScytlKeyStore;

                tenantActivatorTools.getCertificateChains(cryptoAPIScytlKeyStore);
                times = 1;
                result = certificateChains;

                tenantSysKeys.addCertificateChains(tenantID, certificateChains);
                times = 1;
            }
        };

        _target.activateFromDB(tenantActivationData);
    }
}
