package net.minecraft.world.entity.raid;

import java.util.AbstractList;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.dimension.Dimension;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.CompoundTag;
import javax.annotation.Nullable;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.stats.Stats;
import net.minecraft.world.entity.player.Player;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.phys.Vec3;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.world.entity.ai.village.poi.PoiRecord;
import java.util.List;
import net.minecraft.world.entity.Entity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.server.level.ServerPlayer;
import java.util.Iterator;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.level.GameRules;
import com.google.common.collect.Maps;
import net.minecraft.server.level.ServerLevel;
import java.util.Map;
import net.minecraft.world.level.saveddata.SavedData;

public class Raids extends SavedData {
    private final Map<Integer, Raid> raidMap;
    private final ServerLevel level;
    private int nextAvailableID;
    private int tick;
    
    public Raids(final ServerLevel xd) {
        super(getFileId(xd.dimension));
        this.raidMap = Maps.newHashMap();
        this.level = xd;
        this.nextAvailableID = 1;
        this.setDirty();
    }
    
    public Raid get(final int integer) {
        return this.raidMap.get(integer);
    }
    
    public void tick() {
        ++this.tick;
        final Iterator<Raid> iterator2 = this.raidMap.values().iterator();
        while (iterator2.hasNext()) {
            final Raid azn3 = iterator2.next();
            if (this.level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) {
                azn3.stop();
            }
            if (azn3.isStopped()) {
                iterator2.remove();
                this.setDirty();
            }
            else {
                azn3.tick();
            }
        }
        if (this.tick % 200 == 0) {
            this.setDirty();
        }
        DebugPackets.sendRaids(this.level, this.raidMap.values());
    }
    
    public static boolean canJoinRaid(final Raider azo, final Raid azn) {
        return azo != null && azn != null && azn.getLevel() != null && azo.isAlive() && azo.canJoinRaid() && azo.getNoActionTime() <= 2400 && azo.level.getDimension().getType() == azn.getLevel().getDimension().getType();
    }
    
    @Nullable
    public Raid createOrExtendRaid(final ServerPlayer xe) {
        if (xe.isSpectator()) {
            return null;
        }
        if (this.level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) {
            return null;
        }
        final DimensionType cbi3 = xe.level.getDimension().getType();
        if (cbi3 == DimensionType.NETHER) {
            return null;
        }
        final BlockPos fk4 = new BlockPos(xe);
        final List<PoiRecord> list6 = this.level.getPoiManager().getInRange(PoiType.ALL, fk4, 64, PoiManager.Occupancy.IS_OCCUPIED).collect(Collectors.toList());
        int integer7 = 0;
        Vec3 cvl8 = Vec3.ZERO;
        for (final PoiRecord ass10 : list6) {
            final BlockPos fk5 = ass10.getPos();
            cvl8 = cvl8.add(fk5.getX(), fk5.getY(), fk5.getZ());
            ++integer7;
        }
        BlockPos fk6;
        if (integer7 > 0) {
            cvl8 = cvl8.scale(1.0 / integer7);
            fk6 = new BlockPos(cvl8);
        }
        else {
            fk6 = fk4;
        }
        final Raid azn9 = this.getOrCreateRaid(xe.getLevel(), fk6);
        boolean boolean10 = false;
        if (!azn9.isStarted()) {
            if (!this.raidMap.containsKey(azn9.getId())) {
                this.raidMap.put(azn9.getId(), azn9);
            }
            boolean10 = true;
        }
        else if (azn9.getBadOmenLevel() < azn9.getMaxBadOmenLevel()) {
            boolean10 = true;
        }
        else {
            xe.removeEffect(MobEffects.BAD_OMEN);
            xe.connection.send(new ClientboundEntityEventPacket(xe, (byte)43));
        }
        if (boolean10) {
            azn9.absorbBadOmen(xe);
            xe.connection.send(new ClientboundEntityEventPacket(xe, (byte)43));
            if (!azn9.hasFirstWaveSpawned()) {
                xe.awardStat(Stats.RAID_TRIGGER);
                CriteriaTriggers.BAD_OMEN.trigger(xe);
            }
        }
        this.setDirty();
        return azn9;
    }
    
    private Raid getOrCreateRaid(final ServerLevel xd, final BlockPos fk) {
        final Raid azn4 = xd.getRaidAt(fk);
        return (azn4 != null) ? azn4 : new Raid(this.getUniqueId(), xd, fk);
    }
    
    @Override
    public void load(final CompoundTag jt) {
        this.nextAvailableID = jt.getInt("NextAvailableID");
        this.tick = jt.getInt("Tick");
        final ListTag jz3 = jt.getList("Raids", 10);
        for (int integer4 = 0; integer4 < jz3.size(); ++integer4) {
            final CompoundTag jt2 = jz3.getCompound(integer4);
            final Raid azn6 = new Raid(this.level, jt2);
            this.raidMap.put(azn6.getId(), azn6);
        }
    }
    
    @Override
    public CompoundTag save(final CompoundTag jt) {
        jt.putInt("NextAvailableID", this.nextAvailableID);
        jt.putInt("Tick", this.tick);
        final ListTag jz3 = new ListTag();
        for (final Raid azn5 : this.raidMap.values()) {
            final CompoundTag jt2 = new CompoundTag();
            azn5.save(jt2);
            ((AbstractList<CompoundTag>)jz3).add(jt2);
        }
        jt.put("Raids", jz3);
        return jt;
    }
    
    public static String getFileId(final Dimension cbh) {
        return "raids" + cbh.getType().getFileSuffix();
    }
    
    private int getUniqueId() {
        return ++this.nextAvailableID;
    }
    
    @Nullable
    public Raid getNearbyRaid(final BlockPos fk, final int integer) {
        Raid azn4 = null;
        double double5 = integer;
        for (final Raid azn5 : this.raidMap.values()) {
            final double double6 = azn5.getCenter().distSqr(fk);
            if (!azn5.isActive()) {
                continue;
            }
            if (double6 >= double5) {
                continue;
            }
            azn4 = azn5;
            double5 = double6;
        }
        return azn4;
    }
}
