package ru.dbotthepony.mc.otm.mixin;

import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.registries.ForgeRegistries;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;

import java.util.function.Predicate;

@Mixin(Inventory.class)
public class MixinInventory {
	@Final
	@Shadow
	public Player player;

	@Inject(
		method = "add(ILnet/minecraft/world/item/ItemStack;)Z",
		at = @At("HEAD"),
		cancellable = true
	)
	private void add(int pSlot, ItemStack pStack, CallbackInfoReturnable<Boolean> hook) {
		if (pStack.isEmpty()) {
			return;
		}

		if (pSlot == -1) {
			this.player.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
				try {
					hook.setReturnValue(it.inventoryAddImpl(pStack));
				} catch (Throwable throwable) {
					CrashReport crashreport = CrashReport.forThrowable(throwable, "Adding item to inventory (Overdrive That Matters detour)");
					CrashReportCategory crashreportcategory = crashreport.addCategory("Item being added");
					crashreportcategory.setDetail("Registry Name", () -> String.valueOf(ForgeRegistries.ITEMS.getKey(pStack.getItem())));
					crashreportcategory.setDetail("Item Class", () -> pStack.getItem().getClass().getName());
					crashreportcategory.setDetail("Item ID", Item.getId(pStack.getItem()));
					crashreportcategory.setDetail("Item data", pStack.getDamageValue());
					crashreportcategory.setDetail("Item name", () -> pStack.getHoverName().getString());
					throw new ReportedException(crashreport);
				}
			});
		}
	}

	@Inject(
		method = "dropAll()V",
		at = @At("TAIL")
	)
	private void dropAll(CallbackInfo ci) {
		MatteryPlayerCapability.inventoryDropAll((Inventory)(Object)this);
	}

	@Inject(
		method = "clearContent()V",
		at = @At("TAIL")
	)
	private void clearContent(CallbackInfo ci) {
		MatteryPlayerCapability.inventoryClearContent((Inventory)(Object)this);
	}

	@Inject(
		method = "clearOrCountMatchingItems(Ljava/util/function/Predicate;ILnet/minecraft/world/Container;)I",
		at = @At("RETURN"),
		cancellable = true
	)
	private void clearOrCountMatchingItems(Predicate<ItemStack> predicate, int count, Container container, CallbackInfoReturnable<Integer> cir) {
		player.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
			if (!it.getHasExoPack()) return;

			int i = cir.getReturnValue();
			i += ContainerHelper.clearOrCountMatchingItems(it.getExoPackContainer(), predicate, count - i, count == 0);

			cir.setReturnValue(i);
		});
	}
}
