// Path: src/main/java/io/github/sskorol/model/TypeMappings.java
// @AllArgsConstructor
// public enum TypeMappings {
// 
//     COLLECTION(Collection.class, d -> StreamEx.of((Collection<?>) d)),
//     MAP(Map.class, d -> EntryStream.of((Map<?, ?>) d).mapKeyValue(AbstractMap.SimpleEntry::new)),
//     ENTRY(Map.Entry.class, d -> StreamEx.of(((Map.Entry) d).getKey(), ((Map.Entry) d).getValue())),
//     OBJECT_ARRAY(Object[].class, d -> StreamEx.of((Object[]) d)),
//     DOUBLE_ARRAY(double[].class, d -> DoubleStreamEx.of((double[]) d).boxed()),
//     INT_ARRAY(int[].class, d -> IntStreamEx.of((int[]) d).boxed()),
//     LONG_ARRAY(long[].class, d -> LongStreamEx.of((long[]) d).boxed()),
//     STREAM(Stream.class, d -> StreamEx.of((Stream<?>) d)),
//     TUPLE(Tuple.class, d -> StreamEx.of(((Tuple) d).toSeq().toJavaArray()));
// 
//     private final Class<?> typeClass;
//     private final Function<Object, StreamEx<?>> mapper;
// 
//     public boolean isInstanceOf(final Object ob) {
//         return ob != null && typeClass.isAssignableFrom(ob.getClass());
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <T> StreamEx<T> streamOf(final T ob) {
//         return (StreamEx<T>) mapper.apply(ob);
//     }
// }


import io.github.sskorol.core.DataSupplier;
import io.github.sskorol.data.FieldName;
import io.github.sskorol.data.Source;
import io.github.sskorol.model.TypeMappings;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.control.Try;
import lombok.experimental.UtilityClass;
import one.util.streamex.StreamEx;
import org.reflections.Reflections;
import org.testng.ITestNGMethod;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
import org.testng.internal.annotations.IDataProvidable;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.lang.ClassLoader.getSystemResource;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.Optional.ofNullable;
import static org.joor.Reflect.onClass;
    public static <T> Class<T[]> castToArray(final Class<T> entityClass) {
        return (Class<T[]>) (entityClass.isArray() ? entityClass : Array.newInstance(entityClass, 1).getClass());
    }

    @SuppressWarnings("unchecked")
    public static <T> Class<T> castToObject(final Class<T> entityClass) {
        return (Class<T>) (entityClass.isArray() ? entityClass.getComponentType() : entityClass);
    }

    public static String getFieldName(final Field field) {
        var fieldAnnotation = field.getDeclaredAnnotation(FieldName.class);
        return isNull(fieldAnnotation) ? field.getName() : fieldAnnotation.value();
    }

    public static <T> URL getSourcePath(final Class<T> entity) throws IOException {
        return getSourcePath(ofNullable(entity.getDeclaredAnnotation(Source.class))
                .map(Source::path)
                .orElse(""));
    }

    public static URL getSourcePath(final String path) throws IOException {
        return ofNullable(Try.of(() -> new URL(path)).getOrElseGet(ex -> getSystemResource(path)))
                .orElseThrow(() -> new IOException("Unable to access resource specified by " + path + " path"));
    }

    public static <T> StreamEx<T> streamOf(final T data) {
        if (isNull(data)) {
            throw new IllegalArgumentException("Nothing to return from data supplier. Test will be skipped.");
        }

// Path: src/main/java/io/github/sskorol/model/TypeMappings.java
// @AllArgsConstructor
// public enum TypeMappings {
// 
//     COLLECTION(Collection.class, d -> StreamEx.of((Collection<?>) d)),
//     MAP(Map.class, d -> EntryStream.of((Map<?, ?>) d).mapKeyValue(AbstractMap.SimpleEntry::new)),
//     ENTRY(Map.Entry.class, d -> StreamEx.of(((Map.Entry) d).getKey(), ((Map.Entry) d).getValue())),
//     OBJECT_ARRAY(Object[].class, d -> StreamEx.of((Object[]) d)),
//     DOUBLE_ARRAY(double[].class, d -> DoubleStreamEx.of((double[]) d).boxed()),
//     INT_ARRAY(int[].class, d -> IntStreamEx.of((int[]) d).boxed()),
//     LONG_ARRAY(long[].class, d -> LongStreamEx.of((long[]) d).boxed()),
//     STREAM(Stream.class, d -> StreamEx.of((Stream<?>) d)),
//     TUPLE(Tuple.class, d -> StreamEx.of(((Tuple) d).toSeq().toJavaArray()));
// 
//     private final Class<?> typeClass;
//     private final Function<Object, StreamEx<?>> mapper;
// 
//     public boolean isInstanceOf(final Object ob) {
//         return ob != null && typeClass.isAssignableFrom(ob.getClass());
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <T> StreamEx<T> streamOf(final T ob) {
//         return (StreamEx<T>) mapper.apply(ob);
//     }
// }


// Path: src/main/java/io/github/sskorol/utils/ReflectionUtils.java
import io.github.sskorol.core.DataSupplier;
import io.github.sskorol.data.FieldName;
import io.github.sskorol.data.Source;
import io.github.sskorol.model.TypeMappings;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.control.Try;
import lombok.experimental.UtilityClass;
import one.util.streamex.StreamEx;
import org.reflections.Reflections;
import org.testng.ITestNGMethod;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
import org.testng.internal.annotations.IDataProvidable;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.lang.ClassLoader.getSystemResource;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.Optional.ofNullable;
import static org.joor.Reflect.onClass;

    public static <T> Class<T[]> castToArray(final Class<T> entityClass) {
        return (Class<T[]>) (entityClass.isArray() ? entityClass : Array.newInstance(entityClass, 1).getClass());
    }

    @SuppressWarnings("unchecked")
    public static <T> Class<T> castToObject(final Class<T> entityClass) {
        return (Class<T>) (entityClass.isArray() ? entityClass.getComponentType() : entityClass);
    }

    public static String getFieldName(final Field field) {
        var fieldAnnotation = field.getDeclaredAnnotation(FieldName.class);
        return isNull(fieldAnnotation) ? field.getName() : fieldAnnotation.value();
    }

    public static <T> URL getSourcePath(final Class<T> entity) throws IOException {
        return getSourcePath(ofNullable(entity.getDeclaredAnnotation(Source.class))
                .map(Source::path)
                .orElse(""));
    }

    public static URL getSourcePath(final String path) throws IOException {
        return ofNullable(Try.of(() -> new URL(path)).getOrElseGet(ex -> getSystemResource(path)))
                .orElseThrow(() -> new IOException("Unable to access resource specified by " + path + " path"));
    }

    public static <T> StreamEx<T> streamOf(final T data) {
        if (isNull(data)) {
            throw new IllegalArgumentException("Nothing to return from data supplier. Test will be skipped.");
        }

        return StreamEx.of(TypeMappings.values())