/*
 * 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.sdm.infrastructure.ballot;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.iterator.ORecordIteratorClass;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.scytl.products.ov.commons.util.JsonUtils;
import com.scytl.products.ov.sdm.application.exception.DatabaseException;
import com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.sdm.infrastructure.DatabaseFixture;
import com.scytl.products.ov.sdm.infrastructure.DatabaseManager;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

/**
 * Tests of {@link BallotRepositoryImpl}.
 */
public class BallotRepositoryImplTest {
    private DatabaseFixture fixture;

    private DatabaseManager manager;

    private BallotBoxRepository ballotBoxRepository;

    private BallotRepositoryImpl repository;

    @Before
    public void setUp() throws OException, IOException {
        fixture = new DatabaseFixture(getClass());
        fixture.setUp();
        manager = fixture.databaseManager();
        ballotBoxRepository = mock(BallotBoxRepository.class);
        repository = new BallotRepositoryImpl(manager);
        repository.ballotBoxRepository = ballotBoxRepository;
        repository.initialize();
        URL resource =
            getClass().getResource(getClass().getSimpleName() + ".json");
        fixture.createDocuments(repository.entityName(), resource);
    }

    @After
    public void tearDown() {
        fixture.tearDown();
    }

    @Test
    public void testListAliases() {
        List<String> aliases =
            repository.listAliases("3d3da2b8ad05485c9a5daab870e8c1c5");
        assertEquals(1, aliases.size());
        assertEquals("343", aliases.get(0));
    }

    @Test
    public void testListAliasesNotFound() {
        assertTrue(repository.listAliases("unknownBallot").isEmpty());
    }

    @Test
    public void testUpdateRelatedBallotBox() {
        when(ballotBoxRepository
            .listAliases("3d3da2b8ad05485c9a5daab870e8c1c5"))
                .thenReturn(asList("ballotBox1", "ballotBox2"));
        when(ballotBoxRepository
            .listAliases("6770803ba4fa48d0afd1aeb9106af2dc"))
                .thenReturn(asList("ballotBox3", "ballotBox4"));
        repository.updateRelatedBallotBox(
            asList("3d3da2b8ad05485c9a5daab870e8c1c5",
                "6770803ba4fa48d0afd1aeb9106af2dc"));
        try (ODatabaseDocument database = manager.openDatabase()) {
            ORecordIteratorClass<ODocument> iterator =
                database.browseClass(repository.entityName());
            while (iterator.hasNext()) {
                ODocument document = iterator.next();
                String id = document.field(
                    JsonConstants.JSON_ATTRIBUTE_NAME_ID, String.class);
                String ballotBoxes =
                    document.field("ballotBoxes", String.class);
                switch (id) {
                case "3d3da2b8ad05485c9a5daab870e8c1c5":
                    assertEquals("ballotBox1,ballotBox2", ballotBoxes);
                    break;
                case "6770803ba4fa48d0afd1aeb9106af2dc":
                    assertEquals("ballotBox3,ballotBox4", ballotBoxes);
                    break;
                default:
                    assertEquals("56,70,72,85,119,152,176,177,198,203,222",
                        ballotBoxes);
                }
            }
        }
    }

    @Test(expected = DatabaseException.class)
    public void testUpdateRelatedBallotBoxNoyFound() {
        repository.updateRelatedBallotBox(singletonList("unknownBallot"));
    }

    @Test
    public void testUpdateSignedBallot() {
        repository.updateSignedBallot("3d3da2b8ad05485c9a5daab870e8c1c5",
            "signedBallot");
        String json = repository.find("3d3da2b8ad05485c9a5daab870e8c1c5");
        JsonObject object = JsonUtils.getJsonObject(json);
        assertEquals("signedBallot", object
            .getString(JsonConstants.JSON_ATTRIBUTE_NAME_SIGNED_OBJECT));
    }

    @Test(expected = DatabaseException.class)
    public void testUpdateSignedBallotNotFound() {
        repository.updateSignedBallot("unknownObject", "signedBallot");
    }

    @Test
    public void testListByElectionEvent() {
        String json = repository
            .listByElectionEvent("101549c5a4a04c7b88a0cb9be8ab3df6");
        JsonArray array = JsonUtils.getJsonObject(json)
            .getJsonArray(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT);
        assertEquals(2, array.size());
        Set<String> ids = new HashSet<>();
        for (JsonValue value : array) {
            ids.add(((JsonObject) value)
                .getString(JsonConstants.JSON_ATTRIBUTE_NAME_ID));
        }
        assertTrue(
            ids.containsAll(asList("3d3da2b8ad05485c9a5daab870e8c1c5",
                "6770803ba4fa48d0afd1aeb9106af2dc")));
    }

    @Test
    public void testListByElectionEventNotFound() {
        String json =
            repository.listByElectionEvent("unknowElectionEvent");
        JsonArray array = JsonUtils.getJsonObject(json)
            .getJsonArray(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT);
        assertTrue(array.isEmpty());
    }
}
