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

import java.security.Security;
import java.util.Optional;

import javax.inject.Inject;
import javax.persistence.EntityManager;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.scytl.products.ov.ea.domain.model.extendedauthentication.ExtendedAuthentication;

import de.akquinet.jbosscc.needle.annotation.ObjectUnderTest;
import de.akquinet.jbosscc.needle.db.transaction.TransactionHelper;
import de.akquinet.jbosscc.needle.db.transaction.VoidRunnable;
import de.akquinet.jbosscc.needle.junit.DatabaseRule;
import de.akquinet.jbosscc.needle.junit.NeedleRule;

/**
 * $Id$
 *
 * @author Danilo Ascione
 * @date 22/03/16 11:19 Copyright (C) 2016 Scytl Secure Electronic Voting SA All
 *       rights reserved.
 */
public class ExtendedAuthenticationRepositoryImplTest {

    @Rule
    public DatabaseRule databaseRule = new DatabaseRule();

    @Inject
    private EntityManager entityManager;

    @Rule
    public NeedleRule needleRule = new NeedleRule(databaseRule);

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @ObjectUnderTest
    private ExtendedAuthenticationRepositoryImpl sut;

    private TransactionHelper transactionHelper = databaseRule.getTransactionHelper();

    Optional<ExtendedAuthentication> extendedAuthenticationFromDb = null;

    @BeforeClass
    public static void setUp() {
        Security.addProvider(new BouncyCastleProvider());
    }

    @Test
    public void find() throws Exception {
        ExtendedAuthentication extendedAuthentication = buildAndSave(VOTING_CARD_ID_2);
        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {

                extendedAuthenticationFromDb = sut.getForUpdate(TENANT_ID, VOTING_CARD_ID_2, ELECTION_EVENT);
            }
        });

        Assert.assertNotNull(extendedAuthenticationFromDb);
        Assert.assertEquals(ENCRYPTED_START_VOTING_KEY,
            extendedAuthenticationFromDb.get().getEncryptedStartVotingKey());
        Assert.assertEquals(extendedAuthentication.getAuthId(), extendedAuthenticationFromDb.get().getAuthId());
        Assert.assertEquals(extendedAuthentication.getTenantId(), extendedAuthenticationFromDb.get().getTenantId());
        Assert.assertEquals(extendedAuthentication.getElectionEvent(),
            extendedAuthenticationFromDb.get().getElectionEvent());
    }

    @Test
    public void getWithoutLockingSuccessful() throws Exception {
        ExtendedAuthentication extendedAuthentication = buildAndSave(VOTING_CARD_ID_2);
        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {

                extendedAuthenticationFromDb = sut.getForRead(TENANT_ID, VOTING_CARD_ID_2, ELECTION_EVENT);
            }
        });

        Assert.assertNotNull(extendedAuthenticationFromDb);
        Assert.assertEquals(ENCRYPTED_START_VOTING_KEY,
            extendedAuthenticationFromDb.get().getEncryptedStartVotingKey());
        Assert.assertEquals(extendedAuthentication.getAuthId(), extendedAuthenticationFromDb.get().getAuthId());
        Assert.assertEquals(extendedAuthentication.getTenantId(), extendedAuthenticationFromDb.get().getTenantId());
        Assert.assertEquals(extendedAuthentication.getElectionEvent(),
            extendedAuthenticationFromDb.get().getElectionEvent());
    }

    @Test
    public void not_found() throws Exception {
        buildAndSave("Voting Card Id");
        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {
                extendedAuthenticationFromDb = sut.getForUpdate(TENANT_ID, "NOT_IN_DB", ELECTION_EVENT);
            }
        });
        Assert.assertFalse(extendedAuthenticationFromDb.isPresent());
    }

    @Test
    public void update() throws Exception {
        ExtendedAuthentication extendedAuthentication = buildAndSave(VOTING_CARD_ID_2);
        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {
                extendedAuthenticationFromDb = sut.getForUpdate(TENANT_ID, VOTING_CARD_ID_2, ELECTION_EVENT);
            }
        });

        Assert.assertNotNull(extendedAuthenticationFromDb);
        Assert.assertTrue(extendedAuthenticationFromDb.isPresent());
        Assert.assertEquals(ENCRYPTED_START_VOTING_KEY,
            extendedAuthenticationFromDb.get().getEncryptedStartVotingKey());
        Assert.assertEquals(extendedAuthentication.getAuthId(), extendedAuthenticationFromDb.get().getAuthId());
        Assert.assertEquals(extendedAuthentication.getTenantId(), extendedAuthenticationFromDb.get().getTenantId());
        Assert.assertEquals(extendedAuthentication.getElectionEvent(),
            extendedAuthenticationFromDb.get().getElectionEvent());

        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {
                extendedAuthenticationFromDb = sut.getForUpdate(TENANT_ID, VOTING_CARD_ID_2, ELECTION_EVENT);
                sut.delete(extendedAuthenticationFromDb.get());
            }
        });
        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {
                extendedAuthenticationFromDb = sut.getForUpdate(TENANT_ID, VOTING_CARD_ID_2, ELECTION_EVENT);
            }
        });
        Assert.assertNotNull(extendedAuthenticationFromDb);
        Assert.assertFalse(extendedAuthenticationFromDb.isPresent());
    }

    @Test
    public void testGetForReadNotFoundNoException() throws Exception {

        buildAndSave(VOTING_CARD_ID_2);

        transactionHelper.executeInTransaction(new VoidRunnable() {
            @Override
            public void doRun(EntityManager entityManager) throws Exception {
                Optional<ExtendedAuthentication> ea = sut.getForRead("notFound", "notFound", "notFound");
                Assert.assertFalse(ea.isPresent());
            }
        });
    }

    private ExtendedAuthentication buildAndSave(String votingCardId2) {
        return new ExtendedAuthenticationTestdataBuilder(entityManager)
            .withEncryptedStartVotingKey(ENCRYPTED_START_VOTING_KEY).withVotingCardId2(votingCardId2)
            .withTenantId(TENANT_ID).withElectionEvent(ELECTION_EVENT).withAttempts(Integer.valueOf(0))
            .withCredentialId(CREDENTIAL_ID).buildAndSave();
    }

    private static final String VOTING_CARD_ID_2 = "26f4e529b51bca0f5f4fa6f1339a0245;Fk0vw+glXPNlTUnziNKH8w==";

    private static final String ENCRYPTED_START_VOTING_KEY =
        "QzZB//+c1Kn0WjppIsJhfQwuF4RUmdTaJf5YoG9iCaeMbW5en/eMxG+1W2NYkv0e";

    private static final String TENANT_ID = "1";

    private static final String ELECTION_EVENT = "2";

    private static final String CREDENTIAL_ID = "3";

}
