package net.minecraft.world.entity.npc;

import java.util.Iterator;
import javax.annotation.Nullable;
import net.minecraft.world.level.NaturalSpawner;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.animal.horse.TraderLlama;
import java.util.Optional;
import net.minecraft.world.entity.player.Player;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.util.Mth;
import net.minecraft.world.level.GameRules;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.storage.ServerLevelData;
import java.util.Random;
import net.minecraft.world.level.CustomSpawner;

public class WanderingTraderSpawner implements CustomSpawner {
    private final Random random;
    private final ServerLevelData serverLevelData;
    private int tickDelay;
    private int spawnDelay;
    private int spawnChance;
    
    public WanderingTraderSpawner(final ServerLevelData dak) {
        this.random = new Random();
        this.serverLevelData = dak;
        this.tickDelay = 1200;
        this.spawnDelay = dak.getWanderingTraderSpawnDelay();
        this.spawnChance = dak.getWanderingTraderSpawnChance();
        if (this.spawnDelay == 0 && this.spawnChance == 0) {
            dak.setWanderingTraderSpawnDelay(this.spawnDelay = 24000);
            dak.setWanderingTraderSpawnChance(this.spawnChance = 25);
        }
    }
    
    @Override
    public int tick(final ServerLevel zd, final boolean boolean2, final boolean boolean3) {
        if (!zd.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) {
            return 0;
        }
        if (--this.tickDelay > 0) {
            return 0;
        }
        this.tickDelay = 1200;
        this.spawnDelay -= 1200;
        this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
        if (this.spawnDelay > 0) {
            return 0;
        }
        this.spawnDelay = 24000;
        if (!zd.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
            return 0;
        }
        final int integer5 = this.spawnChance;
        this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75);
        this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
        if (this.random.nextInt(100) > integer5) {
            return 0;
        }
        if (this.spawn(zd)) {
            this.spawnChance = 25;
            return 1;
        }
        return 0;
    }
    
    private boolean spawn(final ServerLevel zd) {
        final Player bec3 = zd.getRandomPlayer();
        if (bec3 == null) {
            return true;
        }
        if (this.random.nextInt(10) != 0) {
            return false;
        }
        final BlockPos fu4 = bec3.blockPosition();
        final int integer5 = 48;
        final PoiManager axz6 = zd.getPoiManager();
        final Optional<BlockPos> optional7 = axz6.find(PoiType.MEETING.getPredicate(), fu -> true, fu4, 48, PoiManager.Occupancy.ANY);
        final BlockPos fu5 = optional7.orElse(fu4);
        final BlockPos fu6 = this.findSpawnPositionNear(zd, fu5, 48);
        if (fu6 != null && this.hasEnoughSpace(zd, fu6)) {
            if (zd.getBiome(fu6) == Biomes.THE_VOID) {
                return false;
            }
            final WanderingTrader bdv10 = EntityType.WANDERING_TRADER.spawn(zd, null, null, null, fu6, MobSpawnType.EVENT, false, false);
            if (bdv10 != null) {
                for (int integer6 = 0; integer6 < 2; ++integer6) {
                    this.tryToSpawnLlamaFor(bdv10, 4);
                }
                this.serverLevelData.setWanderingTraderId(bdv10.getUUID());
                bdv10.setDespawnDelay(48000);
                bdv10.setWanderTarget(fu5);
                bdv10.restrictTo(fu5, 16);
                return true;
            }
        }
        return false;
    }
    
    private void tryToSpawnLlamaFor(final WanderingTrader bdv, final int integer) {
        final BlockPos fu4 = this.findSpawnPositionNear(bdv.level, bdv.blockPosition(), integer);
        if (fu4 == null) {
            return;
        }
        final TraderLlama azu5 = EntityType.TRADER_LLAMA.spawn(bdv.level, null, null, null, fu4, MobSpawnType.EVENT, false, false);
        if (azu5 == null) {
            return;
        }
        azu5.setLeashedTo(bdv, true);
    }
    
    @Nullable
    private BlockPos findSpawnPositionNear(final LevelReader bqd, final BlockPos fu, final int integer) {
        BlockPos fu2 = null;
        for (int integer2 = 0; integer2 < 10; ++integer2) {
            final int integer3 = fu.getX() + this.random.nextInt(integer * 2) - integer;
            final int integer4 = fu.getZ() + this.random.nextInt(integer * 2) - integer;
            final int integer5 = bqd.getHeight(Heightmap.Types.WORLD_SURFACE, integer3, integer4);
            final BlockPos fu3 = new BlockPos(integer3, integer5, integer4);
            if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Type.ON_GROUND, bqd, fu3, EntityType.WANDERING_TRADER)) {
                fu2 = fu3;
                break;
            }
        }
        return fu2;
    }
    
    private boolean hasEnoughSpace(final BlockGetter bpg, final BlockPos fu) {
        for (final BlockPos fu2 : BlockPos.betweenClosed(fu, fu.offset(1, 2, 1))) {
            if (!bpg.getBlockState(fu2).getCollisionShape(bpg, fu2).isEmpty()) {
                return false;
            }
        }
        return true;
    }
}
