package CH.ifa.draw.io;

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;

/** Test class for {@link CH.ifa.draw.io.CombinationFileFilter} */
public class CombinationFileFilterTest {
    private CombinationFileFilter _combinationFilter1;
    private CombinationFileFilter _combinationFilter2;
    private CombinationFileFilter _combinationFilter3;
    private SimpleFileFilter _txtFilter;
    private SimpleFileFilter _pngFilter;
    private SimpleFileFilter _jpgFilter;

    @BeforeEach
    void setUp() {
        _combinationFilter1 = new CombinationFileFilter("Combination");
        _combinationFilter2 = new CombinationFileFilter("Combination");
        _combinationFilter3 = new CombinationFileFilter("Combination");
        _txtFilter = new SimpleFileFilter("txt", "Text Files");
        _pngFilter = new SimpleFileFilter("png", "PNG Files");
        _jpgFilter = new SimpleFileFilter("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(
            org.junit.jupiter.params.provider.Arguments.of(txt, true),
            org.junit.jupiter.params.provider.Arguments.of(png, true),
            org.junit.jupiter.params.provider.Arguments.of(pdf, false),
            org.junit.jupiter.params.provider.Arguments.of(null, false),
            org.junit.jupiter.params.provider.Arguments.of(hiddenFile, false));
    }

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

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

    }

    @Test
    void testContains() {
        //given
        _combinationFilter1.add(_pngFilter);
        _combinationFilter1.add(_txtFilter);
        //when/then
        assertThat(_combinationFilter1.contains(_pngFilter)).isTrue();
        assertThat(_combinationFilter1.contains(_txtFilter)).isTrue();
        assertThat(_combinationFilter1.contains(null)).isFalse();
    }

    @Test
    void testAdd() {
        //given/when
        _combinationFilter1.add(_pngFilter);
        //then
        assertThat(_combinationFilter1.contains(_pngFilter)).isTrue();
        //given/when
        boolean secondAdd = _combinationFilter1.add(_pngFilter);
        //then
        assertThat(secondAdd).isFalse();

    }

    @Test
    void testAddAll() {
        //given
        List<SimpleFileFilter> list = Arrays.asList(_txtFilter, _jpgFilter);
        //when
        _combinationFilter1.addAll(list);
        //then
        assertThat(_combinationFilter1.contains(_txtFilter)).isTrue();
        assertThat(_combinationFilter1.contains(_jpgFilter)).isTrue();
    }

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

    @Test
    void testAddAllAddFiltersSecondTime() {
        //given
        _combinationFilter1.add(_pngFilter);
        List<SimpleFileFilter> list = Arrays.asList(_pngFilter, _jpgFilter);
        //when
        _combinationFilter1.addAll(list);
        //then
        assertThat(_combinationFilter1.contains(_pngFilter)).isTrue();
        assertThat(_combinationFilter1.contains(_jpgFilter)).isTrue();
    }

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

    @Test
    void testEquals() {
        //given
        _combinationFilter1.add(_txtFilter);
        _combinationFilter2.add(_txtFilter);
        _combinationFilter3.add(_pngFilter);
        //when/then
        assertThat(_combinationFilter1.equals(_combinationFilter2)).isTrue();
        assertThat(_combinationFilter1.equals(_combinationFilter3)).isFalse();
    }

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

    @Test
    void testHashCode() {
        //given
        _combinationFilter1.add(_txtFilter);
        _combinationFilter2.add(_txtFilter);
        //when
        int hash1 = _combinationFilter1.hashCode();
        int hash2 = _combinationFilter2.hashCode();
        //then
        assertThat(hash1).isEqualTo(hash2);
    }

    @Test
    void testIsEmpty() {
        //given
        _combinationFilter2.add(_pngFilter);
        //when/then
        assertThat(_combinationFilter1.isEmpty()).isTrue();
        assertThat(_combinationFilter2.isEmpty()).isFalse();
    }

    @Test
    void testGetExtensions() {
        //given
        _combinationFilter1.setPreferedFileFilter(_txtFilter);
        //when/then
        assertThat(_combinationFilter1.getExtension()).isEqualTo("txt");
    }

    @Test
    void testAllowHidden() {
        //given/when
        _combinationFilter1.allowHidden(true);
        //then
        assertThat(_combinationFilter1.isHiddenAllowed()).isTrue();
    }

    @Test
    void testAllowDirectory() {
        //given/when
        _combinationFilter1.allowDirectory(false);
        //then
        assertThat(_combinationFilter1.isDirectoryAllowed()).isFalse();
    }
}