package speiger.src.coreengine.assets.api;

import java.io.IOException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.jspecify.annotations.Nullable;

import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
import speiger.src.collections.objects.collections.ObjectIterable;
import speiger.src.collections.objects.collections.ObjectIterator;
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.assets.impl.parsers.Checksums;

public record MultiAsset(ObjectList<IAsset> assets) implements ObjectIterable<IAsset> {
	
	public MultiAsset(ObjectList<IAsset> assets) {
		this.assets = Objects.requireNonNull(assets).unmodifiable();
	}
	
	public MultiAsset(IAsset... assets) {
		this(ObjectArrayList.wrap(assets));
	}
	
	public int size() { return assets.size(); }
	public IAsset get(int index) { return assets.get(index); }
	@Override
	public ObjectIterator<IAsset> iterator() { return assets.iterator(); }
	public String crc() { return map(Checksums.CRC, () -> "").reduce(new StringBuilder(), StringBuilder::append).toString(); }
	public String sha256() { return map(Checksums.SHA_256, () -> "").reduce(new StringBuilder(), StringBuilder::append).toString(); }
	
	
	public <T> ObjectIterable<T> map(IAssetParser<T> mapper, Supplier<T> defaultValue) {
		return assets.map(E -> {
			try { return E.parse(mapper); }
			catch(IOException e) {
				e.printStackTrace();
				return defaultValue.get();
			}
		});
	}
	
	@Override
	public void forEach(Consumer<? super IAsset> action) {
		assets.forEach(action);
	}
	
	@Override
	public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
		assets.forEach(input, action);
	}
	
	@Override
	public void forEachIndexed(IntObjectConsumer<IAsset> action) {
		assets.forEachIndexed(action);
	}
	
	@Nullable
	public static MultiAsset combineNonNull(IAssetProvider provider, ID...ids) {
		ObjectList<IAsset> all = new ObjectArrayList<>();
		for(ID id : ids) {
			IAsset entry = provider.get(id);
			if(entry == null) return null;
			all.add(entry);
		}
		return new MultiAsset(all);
	}
	
	public static MultiAsset combine(IAssetProvider provider, ID...ids) {
		return new MultiAsset(ObjectArrayList.wrap(ids).map(provider::get).filter(T -> T != null).pourAsList());
	}
}
