package de.uni_hamburg.fs;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class ConceptSetTest {

    @Test
    void testEmptyConstructor() {
        //given
        ConceptSet conceptSet = new ConceptSet();

        // when & then
        assertThat(conceptSet.isEmpty()).isTrue();
        assertThat(conceptSet.size()).isZero();
    }

    @Test
    void testConstructorWithConcept() {
        // given
        Concept mockConcept = mock(Concept.class);

        // when
        ConceptSet conceptSet = new ConceptSet(mockConcept);

        // then
        assertThat(conceptSet.isEmpty()).isFalse();
        assertThat(conceptSet.size()).isEqualTo(1);
    }

    @Test
    void testAddConcept() {
        // given
        Concept mockConcept = mock(Concept.class);
        ConceptSet conceptSet = new ConceptSet();

        // when
        conceptSet.addConcept(mockConcept);

        // then
        assertThat(conceptSet.isEmpty()).isFalse();
        assertThat(conceptSet.size()).isEqualTo(1);
    }

    @Test
    void testUnite() {
        // given
        Concept mockConcept = mock(Concept.class);
        Concept anotherMockConcept = mock(Concept.class);
        ConceptSet set1 = new ConceptSet(mockConcept);
        ConceptSet set2 = new ConceptSet(anotherMockConcept);

        // when
        set1.unite(set2);

        // then
        assertThat(set1.size()).isEqualTo(2);
    }

    @Test
    void testJoinConceptWithCompatibleConcepts() throws UnificationFailure {
        // given
        Concept mockConcept = mock(Concept.class);
        ConceptSet conceptSet = new ConceptSet();
        when(mockConcept.isa(any(Concept.class))).thenReturn(false);
        when(mockConcept.isNotA(any(Concept.class))).thenReturn(false);

        // when
        conceptSet.joinConcept(mockConcept);

        // then
        assertThat(conceptSet.size()).isEqualTo(1);
    }

    @Test
    void testJoinConceptWithIncompatibleConcepts() {
        // given
        Concept mockConcept = mock(Concept.class);
        Concept incompatibleConcept = mock(Concept.class);
        ConceptSet conceptSet = new ConceptSet(mockConcept);
        when(mockConcept.isNotA(incompatibleConcept)).thenReturn(true);

        // when & then
        assertThatThrownBy(() -> conceptSet.joinConcept(incompatibleConcept))
            .isInstanceOf(UnificationFailure.class);
    }

    @Test
    void testEqualsWithSameContent() {
        // given
        Concept mockConcept = mock(Concept.class);
        ConceptSet set1 = new ConceptSet(mockConcept);
        ConceptSet set2 = new ConceptSet(mockConcept);

        // when & then
        assertThat(set1).isEqualTo(set2);
    }

    @Test
    void testEqualsWithDifferentContent() {
        // given
        Concept mockConcept = mock(Concept.class);
        ConceptSet set1 = new ConceptSet(mockConcept);
        ConceptSet set2 = new ConceptSet(mock(Concept.class));

        // when & then
        assertThat(set1).isNotEqualTo(set2);
    }
}