package net.minecraft.world.item;

import java.util.AbstractList;
import java.util.Collection;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.chat.Component;
import javax.annotation.Nullable;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.stats.Stat;
import net.minecraft.stats.Stats;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.server.level.ServerPlayer;
import java.util.Random;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.entity.Entity;
import com.mojang.math.Quaternion;
import com.mojang.math.Vector3f;
import net.minecraft.world.entity.monster.CrossbowAttackMob;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import java.util.function.Predicate;
import net.minecraft.resources.ResourceLocation;

public class CrossbowItem extends ProjectileWeaponItem {
    private boolean startSoundPlayed;
    private boolean midLoadSoundPlayed;
    
    public CrossbowItem(final Properties a) {
        super(a);
        this.startSoundPlayed = false;
        this.midLoadSoundPlayed = false;
        this.addProperty(new ResourceLocation("pull"), (ben, bjw, akz) -> {
            if (akz == null || ben.getItem() != this) {
                return 0.0f;
            }
            else if (isCharged(ben)) {
                return 0.0f;
            }
            else {
                return (ben.getUseDuration() - akz.getUseItemRemainingTicks()) / (float)getChargeDuration(ben);
            }
        });
        this.addProperty(new ResourceLocation("pulling"), (ben, bjw, akz) -> (akz != null && akz.isUsingItem() && akz.getUseItem() == ben && !isCharged(ben)) ? 1.0f : 0.0f);
        this.addProperty(new ResourceLocation("charged"), (ben, bjw, akz) -> (akz != null && isCharged(ben)) ? 1.0f : 0.0f);
        this.addProperty(new ResourceLocation("firework"), (ben, bjw, akz) -> (akz != null && isCharged(ben) && containsChargedProjectile(ben, Items.FIREWORK_ROCKET)) ? 1.0f : 0.0f);
    }
    
    @Override
    public Predicate<ItemStack> getSupportedHeldProjectiles() {
        return CrossbowItem.ARROW_OR_FIREWORK;
    }
    
    @Override
    public Predicate<ItemStack> getAllSupportedProjectiles() {
        return CrossbowItem.ARROW_ONLY;
    }
    
    @Override
    public InteractionResultHolder<ItemStack> use(final Level bjw, final Player ayj, final InteractionHand ajk) {
        final ItemStack ben5 = ayj.getItemInHand(ajk);
        if (isCharged(ben5)) {
            performShooting(bjw, ayj, ajk, ben5, getShootingPower(ben5), 1.0f);
            setCharged(ben5, false);
            return InteractionResultHolder.<ItemStack>consume(ben5);
        }
        if (!ayj.getProjectile(ben5).isEmpty()) {
            if (!isCharged(ben5)) {
                this.startSoundPlayed = false;
                this.midLoadSoundPlayed = false;
                ayj.startUsingItem(ajk);
            }
            return InteractionResultHolder.<ItemStack>consume(ben5);
        }
        return InteractionResultHolder.<ItemStack>fail(ben5);
    }
    
    @Override
    public void releaseUsing(final ItemStack ben, final Level bjw, final LivingEntity akz, final int integer) {
        final int integer2 = this.getUseDuration(ben) - integer;
        final float float7 = getPowerForTime(integer2, ben);
        if (float7 >= 1.0f && !isCharged(ben) && tryLoadProjectiles(akz, ben)) {
            setCharged(ben, true);
            final SoundSource aaj8 = (akz instanceof Player) ? SoundSource.PLAYERS : SoundSource.HOSTILE;
            bjw.playSound(null, akz.getX(), akz.getY(), akz.getZ(), SoundEvents.CROSSBOW_LOADING_END, aaj8, 1.0f, 1.0f / (CrossbowItem.random.nextFloat() * 0.5f + 1.0f) + 0.2f);
        }
    }
    
    private static boolean tryLoadProjectiles(final LivingEntity akz, final ItemStack ben) {
        final int integer3 = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MULTISHOT, ben);
        final int integer4 = (integer3 == 0) ? 1 : 3;
        final boolean boolean5 = akz instanceof Player && ((Player)akz).abilities.instabuild;
        ItemStack ben2 = akz.getProjectile(ben);
        ItemStack ben3 = ben2.copy();
        for (int integer5 = 0; integer5 < integer4; ++integer5) {
            if (integer5 > 0) {
                ben2 = ben3.copy();
            }
            if (ben2.isEmpty() && boolean5) {
                ben2 = new ItemStack(Items.ARROW);
                ben3 = ben2.copy();
            }
            if (!loadProjectile(akz, ben, ben2, integer5 > 0, boolean5)) {
                return false;
            }
        }
        return true;
    }
    
    private static boolean loadProjectile(final LivingEntity akz, final ItemStack ben2, final ItemStack ben3, final boolean boolean4, final boolean boolean5) {
        if (ben3.isEmpty()) {
            return false;
        }
        final boolean boolean6 = boolean5 && ben3.getItem() instanceof ArrowItem;
        ItemStack ben4;
        if (!boolean6 && !boolean5 && !boolean4) {
            ben4 = ben3.split(1);
            if (ben3.isEmpty() && akz instanceof Player) {
                ((Player)akz).inventory.removeItem(ben3);
            }
        }
        else {
            ben4 = ben3.copy();
        }
        addChargedProjectile(ben2, ben4);
        return true;
    }
    
    public static boolean isCharged(final ItemStack ben) {
        final CompoundTag jt2 = ben.getTag();
        return jt2 != null && jt2.getBoolean("Charged");
    }
    
    public static void setCharged(final ItemStack ben, final boolean boolean2) {
        final CompoundTag jt3 = ben.getOrCreateTag();
        jt3.putBoolean("Charged", boolean2);
    }
    
    private static void addChargedProjectile(final ItemStack ben1, final ItemStack ben2) {
        final CompoundTag jt3 = ben1.getOrCreateTag();
        ListTag jz4;
        if (jt3.contains("ChargedProjectiles", 9)) {
            jz4 = jt3.getList("ChargedProjectiles", 10);
        }
        else {
            jz4 = new ListTag();
        }
        final CompoundTag jt4 = new CompoundTag();
        ben2.save(jt4);
        ((AbstractList<CompoundTag>)jz4).add(jt4);
        jt3.put("ChargedProjectiles", jz4);
    }
    
    private static List<ItemStack> getChargedProjectiles(final ItemStack ben) {
        final List<ItemStack> list2 = Lists.newArrayList();
        final CompoundTag jt3 = ben.getTag();
        if (jt3 != null && jt3.contains("ChargedProjectiles", 9)) {
            final ListTag jz4 = jt3.getList("ChargedProjectiles", 10);
            if (jz4 != null) {
                for (int integer5 = 0; integer5 < jz4.size(); ++integer5) {
                    final CompoundTag jt4 = jz4.getCompound(integer5);
                    list2.add(ItemStack.of(jt4));
                }
            }
        }
        return list2;
    }
    
    private static void clearChargedProjectiles(final ItemStack ben) {
        final CompoundTag jt2 = ben.getTag();
        if (jt2 != null) {
            final ListTag jz3 = jt2.getList("ChargedProjectiles", 9);
            jz3.clear();
            jt2.put("ChargedProjectiles", jz3);
        }
    }
    
    private static boolean containsChargedProjectile(final ItemStack ben, final Item bei) {
        return getChargedProjectiles(ben).stream().anyMatch(ben -> ben.getItem() == bei);
    }
    
    private static void shootProjectile(final Level bjw, final LivingEntity akz, final InteractionHand ajk, final ItemStack ben4, final ItemStack ben5, final float float6, final boolean boolean7, final float float8, final float float9, final float float10) {
        if (bjw.isClientSide) {
            return;
        }
        final boolean boolean8 = ben5.getItem() == Items.FIREWORK_ROCKET;
        Projectile ayy12;
        if (boolean8) {
            ayy12 = new FireworkRocketEntity(bjw, ben5, akz.getX(), akz.getEyeY() - 0.15000000596046448, akz.getZ(), true);
        }
        else {
            ayy12 = getArrow(bjw, akz, ben4, ben5);
            if (boolean7 || float10 != 0.0f) {
                ((AbstractArrow)ayy12).pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
            }
        }
        if (akz instanceof CrossbowAttackMob) {
            final CrossbowAttackMob awj13 = (CrossbowAttackMob)akz;
            awj13.shootProjectile(awj13.getTarget(), ben4, ayy12, float10);
        }
        else {
            final Vec3 cvl13 = akz.getUpVector(1.0f);
            final Quaternion c14 = new Quaternion(new Vector3f(cvl13), float10, true);
            final Vec3 cvl14 = akz.getViewVector(1.0f);
            final Vector3f e16 = new Vector3f(cvl14);
            e16.transform(c14);
            ayy12.shoot(e16.x(), e16.y(), e16.z(), float8, float9);
        }
        ben4.<LivingEntity>hurtAndBreak(boolean8 ? 3 : 1, akz, akz -> akz.broadcastBreakEvent(ajk));
        bjw.addFreshEntity((Entity)ayy12);
        bjw.playSound(null, akz.getX(), akz.getY(), akz.getZ(), SoundEvents.CROSSBOW_SHOOT, SoundSource.PLAYERS, 1.0f, float6);
    }
    
    private static AbstractArrow getArrow(final Level bjw, final LivingEntity akz, final ItemStack ben3, final ItemStack ben4) {
        final ArrowItem bck5 = (ArrowItem)((ben4.getItem() instanceof ArrowItem) ? ben4.getItem() : Items.ARROW);
        final AbstractArrow ayn6 = bck5.createArrow(bjw, ben4, akz);
        if (akz instanceof Player) {
            ayn6.setCritArrow(true);
        }
        ayn6.setSoundEvent(SoundEvents.CROSSBOW_HIT);
        ayn6.setShotFromCrossbow(true);
        final int integer7 = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.PIERCING, ben3);
        if (integer7 > 0) {
            ayn6.setPierceLevel((byte)integer7);
        }
        return ayn6;
    }
    
    public static void performShooting(final Level bjw, final LivingEntity akz, final InteractionHand ajk, final ItemStack ben, final float float5, final float float6) {
        final List<ItemStack> list7 = getChargedProjectiles(ben);
        final float[] arr8 = getShotPitches(akz.getRandom());
        for (int integer9 = 0; integer9 < list7.size(); ++integer9) {
            final ItemStack ben2 = list7.get(integer9);
            final boolean boolean11 = akz instanceof Player && ((Player)akz).abilities.instabuild;
            if (!ben2.isEmpty()) {
                if (integer9 == 0) {
                    shootProjectile(bjw, akz, ajk, ben, ben2, arr8[integer9], boolean11, float5, float6, 0.0f);
                }
                else if (integer9 == 1) {
                    shootProjectile(bjw, akz, ajk, ben, ben2, arr8[integer9], boolean11, float5, float6, -10.0f);
                }
                else if (integer9 == 2) {
                    shootProjectile(bjw, akz, ajk, ben, ben2, arr8[integer9], boolean11, float5, float6, 10.0f);
                }
            }
        }
        onCrossbowShot(bjw, akz, ben);
    }
    
    private static float[] getShotPitches(final Random random) {
        final boolean boolean2 = random.nextBoolean();
        return new float[] { 1.0f, getRandomShotPitch(boolean2), getRandomShotPitch(!boolean2) };
    }
    
    private static float getRandomShotPitch(final boolean boolean1) {
        final float float2 = boolean1 ? 0.63f : 0.43f;
        return 1.0f / (CrossbowItem.random.nextFloat() * 0.5f + 1.8f) + float2;
    }
    
    private static void onCrossbowShot(final Level bjw, final LivingEntity akz, final ItemStack ben) {
        if (akz instanceof ServerPlayer) {
            final ServerPlayer xe4 = (ServerPlayer)akz;
            if (!bjw.isClientSide) {
                CriteriaTriggers.SHOT_CROSSBOW.trigger(xe4, ben);
            }
            xe4.awardStat(Stats.ITEM_USED.get(ben.getItem()));
        }
        clearChargedProjectiles(ben);
    }
    
    @Override
    public void onUseTick(final Level bjw, final LivingEntity akz, final ItemStack ben, final int integer) {
        if (!bjw.isClientSide) {
            final int integer2 = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, ben);
            final SoundEvent aah7 = this.getStartSound(integer2);
            final SoundEvent aah8 = (integer2 == 0) ? SoundEvents.CROSSBOW_LOADING_MIDDLE : null;
            final float float9 = (ben.getUseDuration() - integer) / (float)getChargeDuration(ben);
            if (float9 < 0.2f) {
                this.startSoundPlayed = false;
                this.midLoadSoundPlayed = false;
            }
            if (float9 >= 0.2f && !this.startSoundPlayed) {
                this.startSoundPlayed = true;
                bjw.playSound(null, akz.getX(), akz.getY(), akz.getZ(), aah7, SoundSource.PLAYERS, 0.5f, 1.0f);
            }
            if (float9 >= 0.5f && aah8 != null && !this.midLoadSoundPlayed) {
                this.midLoadSoundPlayed = true;
                bjw.playSound(null, akz.getX(), akz.getY(), akz.getZ(), aah8, SoundSource.PLAYERS, 0.5f, 1.0f);
            }
        }
    }
    
    @Override
    public int getUseDuration(final ItemStack ben) {
        return getChargeDuration(ben) + 3;
    }
    
    public static int getChargeDuration(final ItemStack ben) {
        final int integer2 = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, ben);
        return (integer2 == 0) ? 25 : (25 - 5 * integer2);
    }
    
    @Override
    public UseAnim getUseAnimation(final ItemStack ben) {
        return UseAnim.CROSSBOW;
    }
    
    private SoundEvent getStartSound(final int integer) {
        switch (integer) {
            case 1: {
                return SoundEvents.CROSSBOW_QUICK_CHARGE_1;
            }
            case 2: {
                return SoundEvents.CROSSBOW_QUICK_CHARGE_2;
            }
            case 3: {
                return SoundEvents.CROSSBOW_QUICK_CHARGE_3;
            }
            default: {
                return SoundEvents.CROSSBOW_LOADING_START;
            }
        }
    }
    
    private static float getPowerForTime(final int integer, final ItemStack ben) {
        float float3 = integer / (float)getChargeDuration(ben);
        if (float3 > 1.0f) {
            float3 = 1.0f;
        }
        return float3;
    }
    
    @Override
    public void appendHoverText(final ItemStack ben, @Nullable final Level bjw, final List<Component> list, final TooltipFlag bfw) {
        final List<ItemStack> list2 = getChargedProjectiles(ben);
        if (!isCharged(ben) || list2.isEmpty()) {
            return;
        }
        final ItemStack ben2 = list2.get(0);
        list.add(new TranslatableComponent("item.minecraft.crossbow.projectile", new Object[0]).append(" ").append(ben2.getDisplayName()));
        if (bfw.isAdvanced() && ben2.getItem() == Items.FIREWORK_ROCKET) {
            final List<Component> list3 = Lists.newArrayList();
            Items.FIREWORK_ROCKET.appendHoverText(ben2, bjw, list3, bfw);
            if (!list3.isEmpty()) {
                for (int integer9 = 0; integer9 < list3.size(); ++integer9) {
                    list3.set(integer9, new TextComponent("  ").append(list3.get(integer9)).withStyle(ChatFormatting.GRAY));
                }
                list.addAll(list3);
            }
        }
    }
    
    private static float getShootingPower(final ItemStack ben) {
        if (ben.getItem() == Items.CROSSBOW && containsChargedProjectile(ben, Items.FIREWORK_ROCKET)) {
            return 1.6f;
        }
        return 3.15f;
    }
}
