package net.minecraft.world.entity.monster;

import java.util.AbstractList;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.entity.raid.Raid;
import net.minecraft.world.Difficulty;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.BannerItem;
import net.minecraft.world.entity.item.ItemEntity;
import com.mojang.math.Quaternion;
import com.mojang.math.Vector3f;
import net.minecraft.world.phys.Vec3;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.CrossbowItem;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.MobType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.enchantment.Enchantment;
import java.util.Map;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import com.google.common.collect.Maps;
import net.minecraft.world.level.ItemLike;
import javax.annotation.Nullable;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.LevelReader;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ItemStack;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.npc.AbstractVillager;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.entity.ai.goal.RangedCrossbowAttackGoal;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.SimpleContainer;
import net.minecraft.network.syncher.EntityDataAccessor;

public class Pillager extends AbstractIllager implements CrossbowAttackMob, RangedAttackMob {
    private static final EntityDataAccessor<Boolean> IS_CHARGING_CROSSBOW;
    private final SimpleContainer inventory;
    
    public Pillager(final EntityType<? extends Pillager> aku, final Level bjw) {
        super(aku, bjw);
        this.inventory = new SimpleContainer(5);
    }
    
    @Override
    protected void registerGoals() {
        super.registerGoals();
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(2, new HoldGroundAttackGoal(this, 10.0f));
        this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0, 8.0f));
        this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6));
        this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0f, 1.0f));
        this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0f));
        this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[] { Raider.class }).setAlertOthers(new Class[0]));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.3499999940395355);
        this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(24.0);
        this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(5.0);
        this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(32.0);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(Pillager.IS_CHARGING_CROSSBOW, false);
    }
    
    public boolean isChargingCrossbow() {
        return this.entityData.<Boolean>get(Pillager.IS_CHARGING_CROSSBOW);
    }
    
    @Override
    public void setChargingCrossbow(final boolean boolean1) {
        this.entityData.<Boolean>set(Pillager.IS_CHARGING_CROSSBOW, boolean1);
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        final ListTag jz3 = new ListTag();
        for (int integer4 = 0; integer4 < this.inventory.getContainerSize(); ++integer4) {
            final ItemStack ben5 = this.inventory.getItem(integer4);
            if (!ben5.isEmpty()) {
                ((AbstractList<CompoundTag>)jz3).add(ben5.save(new CompoundTag()));
            }
        }
        jt.put("Inventory", jz3);
    }
    
    @Override
    public IllagerArmPose getArmPose() {
        if (this.isChargingCrossbow()) {
            return IllagerArmPose.CROSSBOW_CHARGE;
        }
        if (this.isHolding(Items.CROSSBOW)) {
            return IllagerArmPose.CROSSBOW_HOLD;
        }
        if (this.isAggressive()) {
            return IllagerArmPose.ATTACKING;
        }
        return IllagerArmPose.NEUTRAL;
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        final ListTag jz3 = jt.getList("Inventory", 10);
        for (int integer4 = 0; integer4 < jz3.size(); ++integer4) {
            final ItemStack ben5 = ItemStack.of(jz3.getCompound(integer4));
            if (!ben5.isEmpty()) {
                this.inventory.addItem(ben5);
            }
        }
        this.setCanPickUpLoot(true);
    }
    
    @Override
    public float getWalkTargetValue(final BlockPos fk, final LevelReader bjz) {
        final Block bph4 = bjz.getBlockState(fk.below()).getBlock();
        if (bph4 == Blocks.GRASS_BLOCK || bph4 == Blocks.SAND) {
            return 10.0f;
        }
        return 0.5f - bjz.getBrightness(fk);
    }
    
    @Override
    public int getMaxSpawnClusterSize() {
        return 1;
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bjx, final DifficultyInstance ajj, final MobSpawnType alc, @Nullable final SpawnGroupData alm, @Nullable final CompoundTag jt) {
        this.populateDefaultEquipmentSlots(ajj);
        this.populateDefaultEquipmentEnchantments(ajj);
        return super.finalizeSpawn(bjx, ajj, alc, alm, jt);
    }
    
    @Override
    protected void populateDefaultEquipmentSlots(final DifficultyInstance ajj) {
        final ItemStack ben3 = new ItemStack(Items.CROSSBOW);
        if (this.random.nextInt(300) == 0) {
            final Map<Enchantment, Integer> map4 = Maps.newHashMap();
            map4.put(Enchantments.PIERCING, 1);
            EnchantmentHelper.setEnchantments(map4, ben3);
        }
        this.setItemSlot(EquipmentSlot.MAINHAND, ben3);
    }
    
    @Override
    public boolean isAlliedTo(final Entity akq) {
        return super.isAlliedTo(akq) || (akq instanceof LivingEntity && ((LivingEntity)akq).getMobType() == MobType.ILLAGER && this.getTeam() == null && akq.getTeam() == null);
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        return SoundEvents.PILLAGER_AMBIENT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.PILLAGER_DEATH;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource ajz) {
        return SoundEvents.PILLAGER_HURT;
    }
    
    @Override
    public void performRangedAttack(final LivingEntity akz, final float float2) {
        final InteractionHand ajk4 = ProjectileUtil.getWeaponHoldingHand(this, Items.CROSSBOW);
        final ItemStack ben5 = this.getItemInHand(ajk4);
        if (this.isHolding(Items.CROSSBOW)) {
            CrossbowItem.performShooting(this.level, this, ajk4, ben5, 1.6f, (float)(14 - this.level.getDifficulty().getId() * 4));
        }
        this.noActionTime = 0;
    }
    
    @Override
    public void shootProjectile(final LivingEntity akz, final ItemStack ben, final Projectile ayy, final float float4) {
        final Entity akq6 = (Entity)ayy;
        final double double7 = akz.getX() - this.getX();
        final double double8 = akz.getZ() - this.getZ();
        final double double9 = Mth.sqrt(double7 * double7 + double8 * double8);
        final double double10 = akz.getY(0.3333333333333333) - akq6.getY() + double9 * 0.20000000298023224;
        final Vector3f e15 = this.getProjectileShotVector(new Vec3(double7, double10, double8), float4);
        ayy.shoot(e15.x(), e15.y(), e15.z(), 1.6f, (float)(14 - this.level.getDifficulty().getId() * 4));
        this.playSound(SoundEvents.CROSSBOW_SHOOT, 1.0f, 1.0f / (this.getRandom().nextFloat() * 0.4f + 0.8f));
    }
    
    private Vector3f getProjectileShotVector(final Vec3 cvl, final float float2) {
        final Vec3 cvl2 = cvl.normalize();
        Vec3 cvl3 = cvl2.cross(new Vec3(0.0, 1.0, 0.0));
        if (cvl3.lengthSqr() <= 1.0E-7) {
            cvl3 = cvl2.cross(this.getUpVector(1.0f));
        }
        final Quaternion c6 = new Quaternion(new Vector3f(cvl3), 90.0f, true);
        final Vector3f e7 = new Vector3f(cvl2);
        e7.transform(c6);
        final Quaternion c7 = new Quaternion(e7, float2, true);
        final Vector3f e8 = new Vector3f(cvl2);
        e8.transform(c7);
        return e8;
    }
    
    @Override
    protected void pickUpItem(final ItemEntity awb) {
        final ItemStack ben3 = awb.getItem();
        if (ben3.getItem() instanceof BannerItem) {
            super.pickUpItem(awb);
        }
        else {
            final Item bei4 = ben3.getItem();
            if (this.wantsItem(bei4)) {
                final ItemStack ben4 = this.inventory.addItem(ben3);
                if (ben4.isEmpty()) {
                    awb.remove();
                }
                else {
                    ben3.setCount(ben4.getCount());
                }
            }
        }
    }
    
    private boolean wantsItem(final Item bei) {
        return this.hasActiveRaid() && bei == Items.WHITE_BANNER;
    }
    
    @Override
    public boolean setSlot(final int integer, final ItemStack ben) {
        if (super.setSlot(integer, ben)) {
            return true;
        }
        final int integer2 = integer - 300;
        if (integer2 >= 0 && integer2 < this.inventory.getContainerSize()) {
            this.inventory.setItem(integer2, ben);
            return true;
        }
        return false;
    }
    
    @Override
    public void applyRaidBuffs(final int integer, final boolean boolean2) {
        final Raid azn4 = this.getCurrentRaid();
        final boolean boolean3 = this.random.nextFloat() <= azn4.getEnchantOdds();
        if (boolean3) {
            final ItemStack ben6 = new ItemStack(Items.CROSSBOW);
            final Map<Enchantment, Integer> map7 = Maps.newHashMap();
            if (integer > azn4.getNumGroups(Difficulty.NORMAL)) {
                map7.put(Enchantments.QUICK_CHARGE, 2);
            }
            else if (integer > azn4.getNumGroups(Difficulty.EASY)) {
                map7.put(Enchantments.QUICK_CHARGE, 1);
            }
            map7.put(Enchantments.MULTISHOT, 1);
            EnchantmentHelper.setEnchantments(map7, ben6);
            this.setItemSlot(EquipmentSlot.MAINHAND, ben6);
        }
    }
    
    @Override
    public SoundEvent getCelebrateSound() {
        return SoundEvents.PILLAGER_CELEBRATE;
    }
    
    static {
        IS_CHARGING_CROSSBOW = SynchedEntityData.<Boolean>defineId(Pillager.class, EntityDataSerializers.BOOLEAN);
    }
}
