package p.studio.utilities.structures;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public interface ReadOnlySet<T> extends ReadOnlyCollection<T> {
    static <T> ReadOnlySet<T> empty() {
        return wrapInternal(Set.of());
    }

    static <T> ReadOnlySet<T> wrap(final Set<T> set) {
        if (set == null || set.isEmpty()) {
            return ReadOnlySet.empty();
        }
        return wrapInternal(Set.copyOf(set));
    }

    static <T> ReadOnlySet<T> wrap(final Collection<T> collection) {
        if (collection == null || collection.isEmpty()) {
            return ReadOnlySet.empty();
        }
        return wrapInternal(Set.copyOf(collection));
    }

    @SafeVarargs
    static <T> ReadOnlySet<T> from(final T... values) {
        if (values == null || values.length == 0) {
            return ReadOnlySet.empty();
        }
        return ReadOnlySet.wrap(Stream.of(values).collect(Collectors.toSet()));
    }

    private static <T> ReadOnlySet<T> wrapInternal(final Set<T> set) {
        return new ReadOnlySet<>() {
            @Override
            public Set<T> asSet() {
                return set;
            }

            @Override
            public boolean equals(final Object o) {
                if (o == this) return true;
                if (o instanceof ReadOnlySet<?> other) {
                    return asSet().equals(other.asSet());
                }
                return false;
            }

            @Override
            public int hashCode() {
                return set.hashCode();
            }
        };
    }

    Set<T> asSet();

    @Override
    default Collection<T> asCollection() {
        return asSet();
    }

    @Override
    default Stream<T> stream() {
        return asSet().stream();
    }
}
