package asm.mixins;

import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.impl.ClickBlockEvent;
import dev.crucifixbeta.api.events.impl.InteractBlockEvent;
import dev.crucifixbeta.api.events.impl.InteractItemEvent;
import dev.crucifixbeta.mod.modules.impl.player.InteractTweaks;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
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.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Environment(EnvType.CLIENT)
@Mixin({ClientPlayerInteractionManager.class})
public class MixinClientPlayerInteractionManager {
   @Shadow
   private ItemStack selectedStack;

   @ModifyVariable(
      method = {"isCurrentlyBreaking"},
      at = @At("STORE")
   )
   private ItemStack stack(ItemStack stack) {
      return InteractTweaks.INSTANCE.noReset() ? this.selectedStack : stack;
   }

   @ModifyConstant(
      method = {"updateBlockBreakingProgress"},
      constant = {@Constant(
         intValue = 5
      )}
   )
   private int MiningCooldownFix(int value) {
      return InteractTweaks.INSTANCE.noDelay() ? 0 : value;
   }

   @Inject(
      method = {"interactItem"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void hookInteractItem(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
      InteractItemEvent var4 = InteractItemEvent.getPre(hand);
      CrucifixBeta.EVENT_BUS.post(var4);
      if (var4.isCancelled()) {
         cir.setReturnValue(ActionResult.PASS);
      }
   }

   @Inject(
      method = {"interactItem"},
      at = {@At("RETURN")}
   )
   private void hookInteractItemReturn(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
      CrucifixBeta.EVENT_BUS.post(InteractItemEvent.getPost(hand));
   }

   @Inject(
      method = {"interactBlock"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void hookInteractBlock(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
      InteractBlockEvent var5 = InteractBlockEvent.getPre(hand);
      CrucifixBeta.EVENT_BUS.post(var5);
      if (var5.isCancelled()) {
         cir.setReturnValue(ActionResult.PASS);
      }
   }

   @Inject(
      method = {"interactBlock"},
      at = {@At("RETURN")}
   )
   private void hookInteractBlockReturn(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable<ActionResult> cir) {
      CrucifixBeta.EVENT_BUS.post(InteractBlockEvent.getPost(hand));
   }

   @Inject(
      method = {"cancelBlockBreaking"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void hookCancelBlockBreaking(CallbackInfo callbackInfo) {
      if (InteractTweaks.INSTANCE.noAbort()) {
         callbackInfo.cancel();
      }
   }

   @Inject(
      method = {"attackBlock"},
      at = {@At("HEAD")},
      cancellable = true
   )
   private void onAttackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> cir) {
      ClickBlockEvent var4 = ClickBlockEvent.get(pos, direction);
      CrucifixBeta.EVENT_BUS.post(var4);
      if (var4.isCancelled()) {
         cir.setReturnValue(false);
      }
   }
}
