// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.entity.livingentity;

import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.math.shape.Box;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.universe.world.accessor.ChunkAccessor;
import com.hypixel.hytale.server.core.universe.world.accessor.LocalCachedChunkAccessor;
import com.hypixel.hytale.server.core.modules.entity.component.BoundingBox;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.modules.entity.damage.DamageModule;
import com.hypixel.hytale.component.SystemGroup;
import com.hypixel.hytale.server.core.entity.Entity;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.hypixel.hytale.server.core.entity.LivingEntity;
import com.hypixel.hytale.server.core.entity.EntityUtils;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.entity.effect.ActiveEntityEffect;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatMap;
import com.hypixel.hytale.server.core.asset.type.entityeffect.config.EntityEffect;
import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.ArchetypeChunk;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.DisableProcessingAssert;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;

public class LivingEntityEffectSystem extends EntityTickingSystem<EntityStore> implements DisableProcessingAssert
{
    @Nonnull
    private static final Query<EntityStore> QUERY;
    @Nonnull
    private static final String EFFECT_NAME_BURN = "Burn";
    @Nonnull
    private static final String BLOCK_TYPE_FLUID_WATER = "Fluid_Water";
    
    @Nonnull
    @Override
    public Query<EntityStore> getQuery() {
        return LivingEntityEffectSystem.QUERY;
    }
    
    @Override
    public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
        return false;
    }
    
    @Override
    public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        final EffectControllerComponent effectControllerComponent = archetypeChunk.getComponent(index, EffectControllerComponent.getComponentType());
        assert effectControllerComponent != null;
        final Int2ObjectMap<ActiveEntityEffect> activeEffects = effectControllerComponent.getActiveEffects();
        if (activeEffects.isEmpty()) {
            return;
        }
        final IndexedLookupTableAssetMap<String, EntityEffect> entityEffectAssetMap = EntityEffect.getAssetMap();
        final Ref<EntityStore> entityRef = archetypeChunk.getReferenceTo(index);
        final ObjectIterator<ActiveEntityEffect> iterator = activeEffects.values().iterator();
        final EntityStatMap entityStatMapComponent = commandBuffer.getComponent(entityRef, EntityStatMap.getComponentType());
        if (entityStatMapComponent == null) {
            return;
        }
        boolean invalidated = false;
        boolean invulnerable = false;
        while (iterator.hasNext()) {
            final ActiveEntityEffect activeEntityEffect = iterator.next();
            final int entityEffectIndex = activeEntityEffect.getEntityEffectIndex();
            final EntityEffect entityEffect = entityEffectAssetMap.getAsset(entityEffectIndex);
            if (entityEffect == null) {
                iterator.remove();
                invalidated = true;
            }
            else if (!canApplyEffect(entityRef, entityEffect, commandBuffer)) {
                iterator.remove();
                invalidated = true;
            }
            else {
                final float tickDelta = Math.min(activeEntityEffect.getRemainingDuration(), dt);
                activeEntityEffect.tick(commandBuffer, entityRef, entityEffect, entityStatMapComponent, tickDelta);
                if (activeEffects.isEmpty()) {
                    return;
                }
                if (!activeEntityEffect.isInfinite() && activeEntityEffect.getRemainingDuration() <= 0.0f) {
                    iterator.remove();
                    effectControllerComponent.tryResetModelChange(entityRef, activeEntityEffect.getEntityEffectIndex(), commandBuffer);
                    invalidated = true;
                }
                if (!activeEntityEffect.isInvulnerable()) {
                    continue;
                }
                invulnerable = true;
            }
        }
        effectControllerComponent.setInvulnerable(invulnerable);
        if (invalidated) {
            effectControllerComponent.invalidateCache();
            final Entity entity = EntityUtils.getEntity(index, archetypeChunk);
            if (entity instanceof final LivingEntity livingEntity) {
                livingEntity.getStatModifiersManager().setRecalculate(true);
            }
        }
    }
    
    @Nullable
    @Override
    public SystemGroup<EntityStore> getGroup() {
        return DamageModule.get().getGatherDamageGroup();
    }
    
    public static boolean canApplyEffect(@Nonnull final Ref<EntityStore> ownerRef, @Nonnull final EntityEffect entityEffect, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (!"Burn".equals(entityEffect.getId())) {
            return true;
        }
        final TransformComponent transformComponent = componentAccessor.getComponent(ownerRef, TransformComponent.getComponentType());
        assert transformComponent != null;
        final Ref<ChunkStore> chunkRef = transformComponent.getChunkRef();
        if (chunkRef == null || !chunkRef.isValid()) {
            return false;
        }
        final World world = componentAccessor.getExternalData().getWorld();
        final Store<ChunkStore> chunkComponentStore = world.getChunkStore().getStore();
        final WorldChunk worldChunkComponent = chunkComponentStore.getComponent(chunkRef, WorldChunk.getComponentType());
        assert worldChunkComponent != null;
        final BoundingBox boundingBoxComponent = componentAccessor.getComponent(ownerRef, BoundingBox.getComponentType());
        assert boundingBoxComponent != null;
        final Vector3d position = transformComponent.getPosition();
        final Box boundingBox = boundingBoxComponent.getBoundingBox();
        final LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atChunkCoords(world, worldChunkComponent.getX(), worldChunkComponent.getZ(), 1);
        return boundingBox.forEachBlock(position, chunkAccessor, (x, y, z, _chunkAccessor) -> {
            final WorldChunk localChunk = _chunkAccessor.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(x, z));
            if (localChunk == null) {
                return true;
            }
            else {
                final BlockType blockType = localChunk.getBlockType(x, y, z);
                if (blockType == null) {
                    return true;
                }
                else {
                    return !blockType.getId().contains("Fluid_Water");
                }
            }
        });
    }
    
    static {
        QUERY = Query.and(EffectControllerComponent.getComponentType(), TransformComponent.getComponentType(), BoundingBox.getComponentType());
    }
}
