package com.leisuretimedock.blasttravelreborn.content.entity.cannon;

import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
import com.leisuretimedock.blasttravelreborn.api.events.CannonFireEvent;
import com.leisuretimedock.blasttravelreborn.content.entity.CannonEntity;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;

public class CannonBehavior {
	protected static final Vector3f WHITE = new Vector3f(1, 1, 1);
	private static final List<CannonBehavior> ID_TO_BEHAVIOR = new ArrayList<>();
	private static final Object2IntMap<Predicate<ItemStack>> FILTER_TO_BEHAVIOR_ID = new Object2IntOpenHashMap<>();
	private final AtomicBoolean registered = new AtomicBoolean(false);
	private SoundEvent placeInSound = SoundEvents.SAND_PLACE, takeOutSound = SoundEvents.EMPTY;
	public final Item icon;
	public final Predicate<ItemStack> filter;
	private final ResourceLocation texture;

	public CannonBehavior(Item item, ResourceLocation texture) {
		this(item, stack -> stack.getItem() == item, texture);
	}

	public CannonBehavior(Item icon, Predicate<ItemStack> filter) {
		this(icon, filter, BlastTravelReborn.id("textures/entity/cannon/regular.png"));
	}

	public CannonBehavior(Item icon, Predicate<ItemStack> filter, ResourceLocation texture) {
		this.icon = icon;
		this.filter = filter;
		this.texture = texture;
	}

	public void setPlaceInSound(SoundEvent placeInSound) {
		this.placeInSound = placeInSound;
	}

	public SoundEvent getPlaceInSound() {
		return placeInSound;
	}

	public SoundEvent getTakeOutSound() {
		return takeOutSound;
	}

	public void setTakeOutSound(SoundEvent takeOutSound) {
		this.takeOutSound = takeOutSound;
	}

	public CannonBehavior register() {
		if (!registered.get()) {
			FILTER_TO_BEHAVIOR_ID.put(this.filter, ID_TO_BEHAVIOR.size());
			ID_TO_BEHAVIOR.add(this);
			registered.set(true);
		}
		return this;
	}

	@OnlyIn(Dist.CLIENT)
	public boolean displayHead(@NotNull CannonEntity entity) {
		return entity.getClientPlayer() != null;
	}

	public boolean occupiesCannon(ItemStack behaviorStack) {
		return false;
	}

	public void onFired(@NotNull CannonEntity cannon, ItemStack behaviorStack, Vec3 velocity) {
		Entity firstPassenger = cannon.getFirstPassenger();
		Player player = null;
		if (firstPassenger instanceof Player player1) {
			player = player1;
		}
		MinecraftForge.EVENT_BUS.post(new CannonFireEvent.Post(cannon, player, behaviorStack, cannon.position(), velocity));
	}

	public static CannonBehavior byId(int id) {
		return ID_TO_BEHAVIOR.get(id);
	}

	public static int idForStack(ItemStack stack) {
		for (var e : FILTER_TO_BEHAVIOR_ID.object2IntEntrySet()) {
			if (e.getKey().test(stack)) {
				return e.getIntValue();
			}
		}
		return 0;
	}

	public static boolean isValidBehaviorStack(ItemStack stack) {
		return FILTER_TO_BEHAVIOR_ID.object2IntEntrySet().stream().anyMatch(e -> e.getKey().test(stack));
	}

	public static Collection<CannonBehavior> allBehaviors() {
		return ID_TO_BEHAVIOR;
	}

	@OnlyIn(Dist.CLIENT)
	public ResourceLocation texture(ItemStack stack) {
		return texture;
	}


	@OnlyIn(Dist.CLIENT)
	public ResourceLocation headTexture(CannonEntity entity) {
		var player = entity.getClientPlayer();
		if (player == null) {
			return new ResourceLocation("missing");
		}

		return player.getSkinTextureLocation();
	}

	@OnlyIn(Dist.CLIENT)
	public Vector3f headColor(CannonEntity entity) {
		return WHITE;
	}

	@OnlyIn(Dist.CLIENT)
	public @Nullable Vector3f fireColor(CannonEntity entity) {
		return null;
	}

}
