package de.uni_hamburg.fs;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import collections.CollectionEnumeration;

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

class ConjunctiveTypeTest {

    @BeforeEach
    void setUp() {
        TypeSystem.newInstance();
    }

    @Test
    void testConstructorWithRestrictedFlag() {
        // given
        ConjunctiveType type = new ConjunctiveType(true);

        // when & then
        assertThat(type).isNotNull();
        assertThat(type.getName()).isEmpty();
    }

    @Test
    void testAddConcept() throws UnificationFailure {
        // given
        ConjunctiveType type = new ConjunctiveType(true);
        Concept mockConcept = mock(Concept.class);
        CollectionEnumeration mockEnum = mock(CollectionEnumeration.class);
        when(mockConcept.appropFeatureNames()).thenReturn(mockEnum);
        when(mockConcept.isExtensional()).thenReturn(false);

        // when
        type.addConcept(mockConcept);

        // then
        ConceptEnumeration concepts = type.concepts();
        assertThat(concepts.hasMoreElements()).isTrue();
        assertThat(concepts.nextConcept()).isEqualTo(mockConcept);
    }

    @Test
    void testSubsumes() {
        // given
        ConjunctiveType type1 = new ConjunctiveType(true);
        ConjunctiveType type2 = new ConjunctiveType(true);

        // when
        boolean result = type1.subsumes(type2);

        // then
        assertThat(result).isTrue();
    }

    @Test
    void testIsExtensional() throws UnificationFailure {
        // given
        ConjunctiveType type = new ConjunctiveType(true);
        Concept mockConcept = mock(Concept.class);
        CollectionEnumeration mockEnum = mock(CollectionEnumeration.class);
        when(mockConcept.appropFeatureNames()).thenReturn(mockEnum);
        when(mockConcept.isExtensional()).thenReturn(true);

        // when
        type.addConcept(mockConcept);

        // then
        assertThat(type.isExtensional()).isTrue();
    }

    @Test
    void testGetInstanceType() {
        // given
        ConjunctiveType type = new ConjunctiveType(true);

        // when
        Type instanceType = type.getInstanceType();

        // then
        assertThat(instanceType).isInstanceOf(ConjunctiveType.class)
            .returns(true, Type::isInstanceType);
    }

    @Test
    void testIsApprop() {
        // given
        ConjunctiveType type = new ConjunctiveType(true);
        Name featureName = new Name("testFeature");

        // when
        boolean result = type.isApprop(featureName);

        // then
        assertThat(result).isFalse();
    }

    @Test
    void testEquals() {
        // given
        ConjunctiveType type1 = new ConjunctiveType(true);
        ConjunctiveType type2 = new ConjunctiveType(true);

        // when & then
        assertThat(type1).isEqualTo(type2);
    }
}