package de.renew.ioontology;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

/** Test class for {@link MultiExtensionFileFilterImpl} */
public class MultiExtensionFileFilterImplTest {
    private MultiExtensionFileFilterImpl _combinationFilter;
    private ExtensionFileFilterImpl _txtFilter;
    private ExtensionFileFilterImpl _pngFilter;
    private ExtensionFileFilterImpl _jpgFilter;

    @BeforeEach
    void setUp() {
        _combinationFilter = new MultiExtensionFileFilterImpl("Combination");
        _txtFilter = new ExtensionFileFilterImpl("txt", "Text Files");
        _pngFilter = new ExtensionFileFilterImpl("png", "PNG Files");
        _jpgFilter = new ExtensionFileFilterImpl("jpg", "JPG Files");

    }

    private static Stream<Arguments> fileProvider() {
        File txt = new File("document.txt");
        File png = new File("image.png");
        File pdf = new File("report.pdf");
        File hiddenFile = new File(".hidden.txt");

        return Stream.of(
            Arguments.of(txt, true), Arguments.of(png, true), Arguments.of(pdf, false),
            Arguments.of(null, false), Arguments.of(hiddenFile, false));
    }

    @ParameterizedTest
    @MethodSource("fileProvider")
    void testAccept(File file, boolean expected) {
        //given
        _combinationFilter.add(_pngFilter);
        _combinationFilter.add(_txtFilter);
        //when/then
        assertThat(_combinationFilter.accept(file)).isEqualTo(expected);
    }

    @Test
    void testAcceptDirectory() {
        //given
        File dir = new File("testDir");
        dir.mkdir();
        //when/then
        assertThat(_combinationFilter.accept(dir)).isTrue();
        dir.delete();

    }

    @Test
    void testAddNewFilter() {
        //when
        boolean added = _combinationFilter.add(_pngFilter);
        //then
        assertThat(added).isTrue();
    }

    @Test
    void testAddContainedFilter() {
        //given
        _combinationFilter.add(_pngFilter);
        //when
        boolean added = _combinationFilter.add(_pngFilter);
        //then
        assertThat(added).isFalse();
    }

    @Test
    void testAddAllAllNewFilters() {
        //given
        List<ExtensionFileFilterImpl> list = Arrays.asList(_txtFilter, _jpgFilter);
        //when
        boolean added = _combinationFilter.addAll(list);
        //then
        assertAll(
            () -> assertThat(added).isTrue(), () -> assertThat(_combinationFilter.getFileFilters())
                .containsExactlyInAnyOrder(_txtFilter, _jpgFilter));
    }

    @Test
    void testAddAllAddEmptyList() {
        //given
        List<ExtensionFileFilterImpl> emptyList = List.of();
        // when
        boolean result = _combinationFilter.addAll(emptyList);
        //then
        assertThat(result).isFalse();
    }

    @Test
    void testAddAllOneNewFilter() {
        //given
        _combinationFilter.add(_pngFilter);
        List<ExtensionFileFilterImpl> list = Arrays.asList(_pngFilter, _jpgFilter);
        //when
        boolean added = _combinationFilter.addAll(list);
        //then
        assertAll(
            () -> assertThat(added).isTrue(), () -> assertThat(_combinationFilter.getFileFilters())
                .containsExactlyInAnyOrder(_pngFilter, _jpgFilter));
    }

    @Test
    void testAddAllFilterUnchanged() {
        //given
        _combinationFilter.add(_pngFilter);
        List<ExtensionFileFilterImpl> list = Arrays.asList(_pngFilter);
        //when
        boolean added = _combinationFilter.addAll(list);
        //then
        assertAll(
            () -> assertThat(added).isFalse(), () -> assertThat(_combinationFilter.getFileFilters())
                .containsExactlyInAnyOrder(_pngFilter));
    }

    @Test
    void testRemove() {
        //given
        _combinationFilter.add(_jpgFilter);
        //when
        _combinationFilter.remove(_jpgFilter);
        //then
        assertThat(_combinationFilter.getFileFilters().contains(_jpgFilter)).isFalse();
    }

    @Test
    void testEqualsIsEqual() {
        //given
        var combinationFilter2 =
            new MultiExtensionFileFilterImpl(_combinationFilter.getDescription());
        _combinationFilter.add(_txtFilter);
        combinationFilter2.add(_txtFilter);

        //when/then
        assertThat(_combinationFilter.equals(combinationFilter2)).isTrue();
    }

    @Test
    void testEqualsOtherExtension() {
        //given
        _combinationFilter.add(_txtFilter);
        var combinationFilter2 =
            new MultiExtensionFileFilterImpl(_combinationFilter.getDescription());
        combinationFilter2.add(_pngFilter);

        //when/then
        assertThat(_combinationFilter.equals(combinationFilter2)).isFalse();
    }

    @Test
    void testEqualsOtherDescription() {
        //given
        MultiExtensionFileFilterImpl filter =
            new MultiExtensionFileFilterImpl("Different description");
        _combinationFilter.add(_txtFilter);
        filter.add(_txtFilter);
        //when/then
        assertThat(filter.equals(_combinationFilter)).isFalse();
    }

    @Test
    void testHashCode() {
        //given
        var combinationFilter2 =
            new MultiExtensionFileFilterImpl(_combinationFilter.getDescription());
        _combinationFilter.add(_txtFilter);
        combinationFilter2.add(_txtFilter);

        //when
        int hash1 = _combinationFilter.hashCode();
        int hash2 = combinationFilter2.hashCode();

        //then
        assertThat(hash1).isEqualTo(hash2);
    }
}