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

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.Json;
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.JsonConstants;

/**
 * Tests of {@link ElectoralAuthorityRepositoryImpl}.
 */
public class ElectoralAuthorityRepositoryImplTest {
    private DatabaseFixture fixture;

    private BallotBoxRepository ballotBoxRepository;

    private ElectoralAuthorityRepositoryImpl repository;

    @Before
    public void setUp() throws OException, IOException {
        fixture = new DatabaseFixture(getClass());
        fixture.setUp();
        ballotBoxRepository = mock(BallotBoxRepository.class);
        repository = new ElectoralAuthorityRepositoryImpl(
            fixture.databaseManager());
        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 testUpdateRelatedBallotBox() {
        JsonObject ballotBoxes =
            Json.createObjectBuilder()
                .add(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT,
                    Json.createArrayBuilder()
                        .add(Json.createObjectBuilder().add(
                            JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "4"))
                        .add(Json.createObjectBuilder().add(
                            JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "5")))
                .build();
        when(ballotBoxRepository
            .findByElectoralAuthority("331279febbb0423298d44ee58702d581"))
                .thenReturn(ballotBoxes.toString());
        ballotBoxes =
            Json.createObjectBuilder()
                .add(JsonConstants.JSON_ATTRIBUTE_NAME_RESULT,
                    Json.createArrayBuilder()
                        .add(Json.createObjectBuilder().add(
                            JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "6"))
                        .add(Json.createObjectBuilder().add(
                            JsonConstants.JSON_ATTRIBUTE_NAME_ALIAS, "7")))
                .build();
        when(ballotBoxRepository
            .findByElectoralAuthority("331279febbb0423298d44ee58702d582"))
                .thenReturn(ballotBoxes.toString());
        repository.updateRelatedBallotBox(
            asList("331279febbb0423298d44ee58702d581",
                "331279febbb0423298d44ee58702d582"));
        try (ODatabaseDocument database =
            fixture.databaseManager().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);
                List<String> aliases = document.field(
                    JsonConstants.JSON_ATTRIBUTE_NAME_BALLOT_BOX_ALIAS,
                    List.class);
                switch (id) {
                case "331279febbb0423298d44ee58702d581":
                    assertEquals(2, aliases.size());
                    assertEquals("4", aliases.get(0));
                    assertEquals("5", aliases.get(1));
                    break;
                case "331279febbb0423298d44ee58702d582":
                    assertEquals(2, aliases.size());
                    assertEquals("6", aliases.get(0));
                    assertEquals("7", aliases.get(1));
                    break;
                default:
                    assertEquals(1, aliases.size());
                    assertEquals("3", aliases.get(0));
                    break;
                }
            }
        }
    }

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

    @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.contains("331279febbb0423298d44ee58702d581"));
        assertTrue(ids.contains("331279febbb0423298d44ee58702d582"));
    }

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