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.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.core.BlockPos;
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.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerLevel;
import com.mojang.datafixers.Dynamic;
import com.mojang.datafixers.types.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> aku, final Level bjw) {
        super(aku, bjw);
        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 jt) {
        super.addAdditionalSaveData(jt);
        jt.put("VillagerData", this.getVillagerData().<Tag>serialize((com.mojang.datafixers.types.DynamicOps<Tag>)NbtOps.INSTANCE));
        if (this.tradeOffers != null) {
            jt.put("Offers", this.tradeOffers);
        }
        if (this.gossips != null) {
            jt.put("Gossips", this.gossips);
        }
        jt.putInt("ConversionTime", this.isConverting() ? this.villagerConversionTime : -1);
        if (this.conversionStarter != null) {
            jt.putUUID("ConversionPlayer", this.conversionStarter);
        }
        jt.putInt("Xp", this.villagerXp);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        if (jt.contains("VillagerData", 10)) {
            this.setVillagerData(new VillagerData(new Dynamic((DynamicOps)NbtOps.INSTANCE, jt.get("VillagerData"))));
        }
        if (jt.contains("Offers", 10)) {
            this.tradeOffers = jt.getCompound("Offers");
        }
        if (jt.contains("Gossips", 10)) {
            this.gossips = jt.getList("Gossips", 10);
        }
        if (jt.contains("ConversionTime", 99) && jt.getInt("ConversionTime") > -1) {
            this.startConverting(jt.hasUUID("ConversionPlayer") ? jt.getUUID("ConversionPlayer") : null, jt.getInt("ConversionTime"));
        }
        if (jt.contains("Xp", 3)) {
            this.villagerXp = jt.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();
    }
    
    @Override
    public boolean mobInteract(final Player ayj, final InteractionHand ajk) {
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        if (ben4.getItem() == Items.GOLDEN_APPLE && this.hasEffect(MobEffects.WEAKNESS)) {
            if (!ayj.abilities.instabuild) {
                ben4.shrink(1);
            }
            if (!this.level.isClientSide) {
                this.startConverting(ayj.getUUID(), this.random.nextInt(2401) + 3600);
                ayj.swing(ajk, true);
            }
            return true;
        }
        return super.mobInteract(ayj, ajk);
    }
    
    @Override
    protected boolean convertsInWater() {
        return false;
    }
    
    @Override
    public boolean removeWhenFarAway(final double double1) {
        return !this.isConverting();
    }
    
    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 xd) {
        final Villager axw3 = EntityType.VILLAGER.create(xd);
        for (final EquipmentSlot akv7 : EquipmentSlot.values()) {
            final ItemStack ben8 = this.getItemBySlot(akv7);
            if (!ben8.isEmpty()) {
                if (EnchantmentHelper.hasBindingCurse(ben8)) {
                    axw3.setSlot(akv7.getIndex() + 300, ben8);
                }
                else {
                    final double double9 = this.getEquipmentDropChance(akv7);
                    if (double9 > 1.0) {
                        this.spawnAtLocation(ben8);
                    }
                }
            }
        }
        axw3.copyPosition(this);
        axw3.setVillagerData(this.getVillagerData());
        if (this.gossips != null) {
            axw3.setGossips(this.gossips);
        }
        if (this.tradeOffers != null) {
            axw3.setOffers(new MerchantOffers(this.tradeOffers));
        }
        axw3.setVillagerXp(this.villagerXp);
        axw3.finalizeSpawn(xd, xd.getCurrentDifficultyAt(new BlockPos(axw3)), MobSpawnType.CONVERSION, null, null);
        if (this.isBaby()) {
            axw3.setAge(-24000);
        }
        this.remove();
        axw3.setNoAi(this.isNoAi());
        if (this.hasCustomName()) {
            axw3.setCustomName(this.getCustomName());
            axw3.setCustomNameVisible(this.isCustomNameVisible());
        }
        if (this.isPersistenceRequired()) {
            axw3.setPersistenceRequired();
        }
        axw3.setInvulnerable(this.isInvulnerable());
        xd.addFreshEntity(axw3);
        if (this.conversionStarter != null) {
            final Player ayj4 = xd.getPlayerByUUID(this.conversionStarter);
            if (ayj4 instanceof ServerPlayer) {
                CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)ayj4, this, axw3);
                xd.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, ayj4, axw3);
            }
        }
        axw3.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));
        xd.levelEvent(null, 1027, new BlockPos(this), 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 bph8 = this.level.getBlockState(a4.set(integer4, integer5, integer6)).getBlock();
                        if (bph8 == Blocks.IRON_BARS || bph8 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 ajz) {
        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 jt) {
        this.tradeOffers = jt;
    }
    
    public void setGossips(final Tag kj) {
        this.gossips = kj;
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bjx, final DifficultyInstance ajj, final MobSpawnType alc, @Nullable final SpawnGroupData alm, @Nullable final CompoundTag jt) {
        this.setVillagerData(this.getVillagerData().setType(VillagerType.byBiome(bjx.getBiome(new BlockPos(this)))));
        return super.finalizeSpawn(bjx, ajj, alc, alm, jt);
    }
    
    public void setVillagerData(final VillagerData axx) {
        final VillagerData axx2 = this.getVillagerData();
        if (axx2.getProfession() != axx.getProfession()) {
            this.tradeOffers = null;
        }
        this.entityData.<VillagerData>set(ZombieVillager.DATA_VILLAGER_DATA, axx);
    }
    
    @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);
    }
}
