package twilightforest.asm.transformers.multipart;

import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.ITransformerVotingContext;
import cpw.mods.modlauncher.api.TargetType;
import cpw.mods.modlauncher.api.TransformerVoteResult;
import net.neoforged.coremod.api.ASMAPI;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import twilightforest.asm.ASMUtil;

import java.util.Optional;
import java.util.Set;

/**
 * {@link twilightforest.ASMHooks#resolveEntityRenderer}
 */
public class ResolveEntityRendererTransformer implements ITransformer<MethodNode> {

	@Override
	public @NotNull MethodNode transform(MethodNode node, ITransformerVotingContext context) {
		ASMUtil.findFieldInstructions(
				node,
				Opcodes.GETFIELD,
				"net/minecraft/client/renderer/entity/EntityRenderDispatcher",
				"renderers"
			).map(searchTarget -> ASMUtil.findMethodInstructions(
				node,
				searchTarget,
				Opcodes.INVOKEINTERFACE,
				"java/util/Map",
				"get",
				"(Ljava/lang/Object;)Ljava/lang/Object;"
			).findFirst().flatMap(searchTarget2 -> ASMUtil.findInstructions(
				node,
				searchTarget2,
				Opcodes.CHECKCAST
			).findFirst())).filter(Optional::isPresent).map(Optional::get)
			.forEach(target -> node.instructions.insert(
				target,
				ASMAPI.listOf(
					new VarInsnNode(Opcodes.ALOAD, 1),
					new MethodInsnNode(
						Opcodes.INVOKESTATIC,
						"twilightforest/ASMHooks",
						"resolveEntityRenderer",
						"(Lnet/minecraft/client/renderer/entity/EntityRenderer;Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/client/renderer/entity/EntityRenderer;"
					)
				)
			));
		return node;
	}

	@Override
	public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) {
		return TransformerVoteResult.YES;
	}

	@Override
	public @NotNull Set<Target<MethodNode>> targets() {
		return Set.of(Target.targetMethod(
			"net.minecraft.client.renderer.entity.EntityRenderDispatcher",
			"getRenderer",
			"(Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/client/renderer/entity/EntityRenderer;"
		));
	}

	@Override
	public @NotNull TargetType<MethodNode> getTargetType() {
		return TargetType.METHOD;
	}

}
