package xyz.twokilohertz.mixin;

import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import xyz.twokilohertz.HotbarReplace;

@Mixin(ItemStack.class)
public class ItemStackMixin {
    Item lastUsedItem = null;

    @Inject(at = @At("HEAD"), method = "use")
    private void ItemStack_use_HEAD(World world, PlayerEntity player, Hand hand,
            CallbackInfoReturnable<ActionResult> info) {
        if (!world.isClient())
            return;

        Item item = player.getStackInHand(hand).getItem();
        if (item == null)
            return;

        lastUsedItem = item;
    }

    @Inject(at = @At("HEAD"), method = "useOnBlock")
    private void ItemStack_useOnBlock_HEAD(ItemUsageContext context,
            CallbackInfoReturnable<ActionResult> info) {
        if (!context.getWorld().isClient())
            return;

        Item item = context.getPlayer().getStackInHand(context.getHand()).getItem();
        if (item == null)
            return;

        lastUsedItem = item;
    }

    @Inject(at = @At("HEAD"), method = "useOnEntity")
    private void ItemStack_useOnEntity_HEAD(PlayerEntity player, LivingEntity entity, Hand hand,
            CallbackInfoReturnable<ActionResult> info) {
        if (!player.getWorld().isClient())
            return;

        Item item = player.getStackInHand(hand).getItem();
        if (item == null)
            return;

        lastUsedItem = item;
    }

    @Inject(at = @At("TAIL"), method = "use")
    private void ItemStack_use_TAIL(World world, PlayerEntity player, Hand hand,
            CallbackInfoReturnable<ActionResult> info) {
        if (!world.isClient())
            return;

        if (info.getReturnValue() != ActionResult.SUCCESS)
            return;

        ItemStack stack = player.getStackInHand(hand);

        if (stack.getCount() > 1)
            return;

        HotbarReplace.tryReplaceSlot(player, hand, lastUsedItem);
    }

    @Inject(at = @At("TAIL"), method = "useOnBlock")
    private void ItemStack_useOnBlock_TAIL(ItemUsageContext context, CallbackInfoReturnable<ActionResult> info) {
        if (!context.getWorld().isClient())
            return;

        if (info.getReturnValue() != ActionResult.SUCCESS)
            return;

        PlayerEntity player = context.getPlayer();
        Hand hand = context.getHand();
        ItemStack stack = player.getStackInHand(hand);

        if (stack.getCount() != 0)
            return;

        HotbarReplace.tryReplaceSlot(player, hand, lastUsedItem);
    }

    @Inject(at = @At("TAIL"), method = "useOnEntity")
    private void ItemStack_useOnEntity_TAIL(PlayerEntity player, LivingEntity entity, Hand hand,
            CallbackInfoReturnable<ActionResult> info) {
        if (info.getReturnValue() != ActionResult.SUCCESS)
            return;

        ItemStack stack = player.getStackInHand(hand);

        if (stack.getCount() > 1)
            return;

        HotbarReplace.tryReplaceSlot(player, hand, lastUsedItem);
    }

    @Inject(at = @At("HEAD"), method = "Lnet/minecraft/item/ItemStack;finishUsing(Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;)Lnet/minecraft/item/ItemStack;")
    private void ItemStack_finishUsing_HEAD(World world, LivingEntity user,
            CallbackInfoReturnable<ItemStack> info) {
        if (!world.isClient())
            return;

        ItemStack stack = (ItemStack) (Object) this;
        // ItemStack stack = info.getReturnValue(); -- only applicable when injecting at TAIL

        if (lastUsedItem != stack.getItem())
            return;

        // Food items disappear into thin (minecraft:)air before their stack size reaches 0
        if (stack.getCount() > 1)
            return;

        if (!user.isPlayer())
            return;

        PlayerEntity player = (PlayerEntity) user;

        if (!player.isMainPlayer())
            return;

        HotbarReplace.tryReplaceSlot(player, player.getActiveHand(), lastUsedItem);
    }
}
