package net.minecraft.world.entity.monster;

import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ReputationEventHandler;
import net.minecraft.world.entity.ai.village.ReputationEventType;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.effect.MobEffectInstance;
import javax.annotation.Nullable;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.item.Items;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerLevel;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Dynamic;
import java.util.function.Consumer;
import com.mojang.serialization.DynamicOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.core.Registry;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import java.util.UUID;
import net.minecraft.world.entity.npc.VillagerData;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.npc.VillagerDataHolder;

public class ZombieVillager extends Zombie implements VillagerDataHolder {
    private static final EntityDataAccessor<Boolean> DATA_CONVERTING_ID;
    private static final EntityDataAccessor<VillagerData> DATA_VILLAGER_DATA;
    private int villagerConversionTime;
    private UUID conversionStarter;
    private Tag gossips;
    private CompoundTag tradeOffers;
    private int villagerXp;
    
    public ZombieVillager(final EntityType<? extends ZombieVillager> aoq, final Level bqb) {
        super(aoq, bqb);
        this.setVillagerData(this.getVillagerData().setProfession(Registry.VILLAGER_PROFESSION.getRandom(this.random)));
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Boolean>define(ZombieVillager.DATA_CONVERTING_ID, false);
        this.entityData.<VillagerData>define(ZombieVillager.DATA_VILLAGER_DATA, new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, 1));
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag le) {
        super.addAdditionalSaveData(le);
        VillagerData.CODEC.encodeStart((DynamicOps)NbtOps.INSTANCE, this.getVillagerData()).resultOrPartial((Consumer)ZombieVillager.LOGGER::error).ifPresent(lu -> le.put("VillagerData", lu));
        if (this.tradeOffers != null) {
            le.put("Offers", this.tradeOffers);
        }
        if (this.gossips != null) {
            le.put("Gossips", this.gossips);
        }
        le.putInt("ConversionTime", this.isConverting() ? this.villagerConversionTime : -1);
        if (this.conversionStarter != null) {
            le.putUUID("ConversionPlayer", this.conversionStarter);
        }
        le.putInt("Xp", this.villagerXp);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        if (le.contains("VillagerData", 10)) {
            final DataResult<VillagerData> dataResult3 = (DataResult<VillagerData>)VillagerData.CODEC.parse(new Dynamic((DynamicOps)NbtOps.INSTANCE, le.get("VillagerData")));
            dataResult3.resultOrPartial((Consumer)ZombieVillager.LOGGER::error).ifPresent(this::setVillagerData);
        }
        if (le.contains("Offers", 10)) {
            this.tradeOffers = le.getCompound("Offers");
        }
        if (le.contains("Gossips", 10)) {
            this.gossips = le.getList("Gossips", 10);
        }
        if (le.contains("ConversionTime", 99) && le.getInt("ConversionTime") > -1) {
            this.startConverting(le.hasUUID("ConversionPlayer") ? le.getUUID("ConversionPlayer") : null, le.getInt("ConversionTime"));
        }
        if (le.contains("Xp", 3)) {
            this.villagerXp = le.getInt("Xp");
        }
    }
    
    @Override
    public void tick() {
        if (!this.level.isClientSide && this.isAlive() && this.isConverting()) {
            final int integer2 = this.getConversionProgress();
            this.villagerConversionTime -= integer2;
            if (this.villagerConversionTime <= 0) {
                this.finishConversion((ServerLevel)this.level);
            }
        }
        super.tick();
    }
    
    public InteractionResult mobInteract(final Player bec, final InteractionHand anf) {
        final ItemStack bki4 = bec.getItemInHand(anf);
        if (bki4.getItem() != Items.GOLDEN_APPLE) {
            return super.mobInteract(bec, anf);
        }
        if (this.hasEffect(MobEffects.WEAKNESS)) {
            if (!bec.abilities.instabuild) {
                bki4.shrink(1);
            }
            if (!this.level.isClientSide) {
                this.startConverting(bec.getUUID(), this.random.nextInt(2401) + 3600);
            }
            return InteractionResult.SUCCESS;
        }
        return InteractionResult.CONSUME;
    }
    
    @Override
    protected boolean convertsInWater() {
        return false;
    }
    
    @Override
    public boolean removeWhenFarAway(final double double1) {
        return !this.isConverting() && this.villagerXp == 0;
    }
    
    public boolean isConverting() {
        return this.getEntityData().<Boolean>get(ZombieVillager.DATA_CONVERTING_ID);
    }
    
    private void startConverting(@Nullable final UUID uUID, final int integer) {
        this.conversionStarter = uUID;
        this.villagerConversionTime = integer;
        this.getEntityData().<Boolean>set(ZombieVillager.DATA_CONVERTING_ID, true);
        this.removeEffect(MobEffects.WEAKNESS);
        this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, integer, Math.min(this.level.getDifficulty().getId() - 1, 0)));
        this.level.broadcastEntityEvent(this, (byte)16);
    }
    
    @Override
    public void handleEntityEvent(final byte byte1) {
        if (byte1 == 16) {
            if (!this.isSilent()) {
                this.level.playLocalSound(this.getX(), this.getEyeY(), this.getZ(), SoundEvents.ZOMBIE_VILLAGER_CURE, this.getSoundSource(), 1.0f + this.random.nextFloat(), this.random.nextFloat() * 0.7f + 0.3f, false);
            }
            return;
        }
        super.handleEntityEvent(byte1);
    }
    
    private void finishConversion(final ServerLevel zd) {
        final Villager bdp3 = EntityType.VILLAGER.create(zd);
        for (final EquipmentSlot aor7 : EquipmentSlot.values()) {
            final ItemStack bki8 = this.getItemBySlot(aor7);
            if (!bki8.isEmpty()) {
                if (EnchantmentHelper.hasBindingCurse(bki8)) {
                    bdp3.setSlot(aor7.getIndex() + 300, bki8);
                }
                else {
                    final double double9 = this.getEquipmentDropChance(aor7);
                    if (double9 > 1.0) {
                        this.spawnAtLocation(bki8);
                    }
                }
            }
        }
        bdp3.copyPosition(this);
        bdp3.setVillagerData(this.getVillagerData());
        if (this.gossips != null) {
            bdp3.setGossips(this.gossips);
        }
        if (this.tradeOffers != null) {
            bdp3.setOffers(new MerchantOffers(this.tradeOffers));
        }
        bdp3.setVillagerXp(this.villagerXp);
        bdp3.finalizeSpawn(zd, zd.getCurrentDifficultyAt(bdp3.blockPosition()), MobSpawnType.CONVERSION, null, null);
        if (this.isBaby()) {
            bdp3.setAge(-24000);
        }
        this.remove();
        bdp3.setNoAi(this.isNoAi());
        if (this.hasCustomName()) {
            bdp3.setCustomName(this.getCustomName());
            bdp3.setCustomNameVisible(this.isCustomNameVisible());
        }
        if (this.isPersistenceRequired()) {
            bdp3.setPersistenceRequired();
        }
        bdp3.setInvulnerable(this.isInvulnerable());
        zd.addFreshEntity(bdp3);
        if (this.conversionStarter != null) {
            final Player bec4 = zd.getPlayerByUUID(this.conversionStarter);
            if (bec4 instanceof ServerPlayer) {
                CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)bec4, this, bdp3);
                zd.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, bec4, bdp3);
            }
        }
        bdp3.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));
        if (!this.isSilent()) {
            zd.levelEvent(null, 1027, this.blockPosition(), 0);
        }
    }
    
    private int getConversionProgress() {
        int integer2 = 1;
        if (this.random.nextFloat() < 0.01f) {
            int integer3 = 0;
            final BlockPos.MutableBlockPos a4 = new BlockPos.MutableBlockPos();
            for (int integer4 = (int)this.getX() - 4; integer4 < (int)this.getX() + 4 && integer3 < 14; ++integer4) {
                for (int integer5 = (int)this.getY() - 4; integer5 < (int)this.getY() + 4 && integer3 < 14; ++integer5) {
                    for (int integer6 = (int)this.getZ() - 4; integer6 < (int)this.getZ() + 4 && integer3 < 14; ++integer6) {
                        final Block bvr8 = this.level.getBlockState(a4.set(integer4, integer5, integer6)).getBlock();
                        if (bvr8 == Blocks.IRON_BARS || bvr8 instanceof BedBlock) {
                            if (this.random.nextFloat() < 0.3f) {
                                ++integer2;
                            }
                            ++integer3;
                        }
                    }
                }
            }
        }
        return integer2;
    }
    
    @Override
    protected float getVoicePitch() {
        if (this.isBaby()) {
            return (this.random.nextFloat() - this.random.nextFloat()) * 0.2f + 2.0f;
        }
        return (this.random.nextFloat() - this.random.nextFloat()) * 0.2f + 1.0f;
    }
    
    public SoundEvent getAmbientSound() {
        return SoundEvents.ZOMBIE_VILLAGER_AMBIENT;
    }
    
    public SoundEvent getHurtSound(final DamageSource anw) {
        return SoundEvents.ZOMBIE_VILLAGER_HURT;
    }
    
    public SoundEvent getDeathSound() {
        return SoundEvents.ZOMBIE_VILLAGER_DEATH;
    }
    
    public SoundEvent getStepSound() {
        return SoundEvents.ZOMBIE_VILLAGER_STEP;
    }
    
    @Override
    protected ItemStack getSkull() {
        return ItemStack.EMPTY;
    }
    
    public void setTradeOffers(final CompoundTag le) {
        this.tradeOffers = le;
    }
    
    public void setGossips(final Tag lu) {
        this.gossips = lu;
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bqc, final DifficultyInstance ane, final MobSpawnType apb, @Nullable final SpawnGroupData apo, @Nullable final CompoundTag le) {
        this.setVillagerData(this.getVillagerData().setType(VillagerType.byBiome(bqc.getBiome(this.blockPosition()))));
        return super.finalizeSpawn(bqc, ane, apb, apo, le);
    }
    
    public void setVillagerData(final VillagerData bdq) {
        final VillagerData bdq2 = this.getVillagerData();
        if (bdq2.getProfession() != bdq.getProfession()) {
            this.tradeOffers = null;
        }
        this.entityData.<VillagerData>set(ZombieVillager.DATA_VILLAGER_DATA, bdq);
    }
    
    @Override
    public VillagerData getVillagerData() {
        return this.entityData.<VillagerData>get(ZombieVillager.DATA_VILLAGER_DATA);
    }
    
    public void setVillagerXp(final int integer) {
        this.villagerXp = integer;
    }
    
    static {
        DATA_CONVERTING_ID = SynchedEntityData.<Boolean>defineId(ZombieVillager.class, EntityDataSerializers.BOOLEAN);
        DATA_VILLAGER_DATA = SynchedEntityData.<VillagerData>defineId(ZombieVillager.class, EntityDataSerializers.VILLAGER_DATA);
    }
}
