package net.minecraft.world.damagesource;

import javax.annotation.Nullable;
import java.util.Iterator;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Optional;
import net.minecraft.world.level.block.Block;
import net.minecraft.tags.Tag;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.core.BlockPos;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.LivingEntity;
import java.util.List;

public class CombatTracker {
    private final List<CombatEntry> entries;
    private final LivingEntity mob;
    private int lastDamageTime;
    private int combatStartTime;
    private int combatEndTime;
    private boolean inCombat;
    private boolean takingDamage;
    private String nextLocation;
    
    public CombatTracker(final LivingEntity aoy) {
        this.entries = Lists.newArrayList();
        this.mob = aoy;
    }
    
    public void prepareForDamage() {
        this.resetPreparedStatus();
        final Optional<BlockPos> optional2 = this.mob.getLastClimbablePos();
        if (optional2.isPresent()) {
            final BlockState cfj3 = this.mob.level.getBlockState(optional2.get());
            if (cfj3.is(Blocks.LADDER) || cfj3.is(BlockTags.TRAPDOORS)) {
                this.nextLocation = "ladder";
            }
            else if (cfj3.is(Blocks.VINE)) {
                this.nextLocation = "vines";
            }
            else if (cfj3.is(Blocks.WEEPING_VINES) || cfj3.is(Blocks.WEEPING_VINES_PLANT)) {
                this.nextLocation = "weeping_vines";
            }
            else if (cfj3.is(Blocks.TWISTING_VINES) || cfj3.is(Blocks.TWISTING_VINES_PLANT)) {
                this.nextLocation = "twisting_vines";
            }
            else if (cfj3.is(Blocks.SCAFFOLDING)) {
                this.nextLocation = "scaffolding";
            }
            else {
                this.nextLocation = "other_climbable";
            }
        }
        else if (this.mob.isInWater()) {
            this.nextLocation = "water";
        }
    }
    
    public void recordDamage(final DamageSource anw, final float float2, final float float3) {
        this.recheckStatus();
        this.prepareForDamage();
        final CombatEntry ant5 = new CombatEntry(anw, this.mob.tickCount, float2, float3, this.nextLocation, this.mob.fallDistance);
        this.entries.add(ant5);
        this.lastDamageTime = this.mob.tickCount;
        this.takingDamage = true;
        if (ant5.isCombatRelated() && !this.inCombat && this.mob.isAlive()) {
            this.inCombat = true;
            this.combatStartTime = this.mob.tickCount;
            this.combatEndTime = this.combatStartTime;
            this.mob.onEnterCombat();
        }
    }
    
    public Component getDeathMessage() {
        if (this.entries.isEmpty()) {
            return new TranslatableComponent("death.attack.generic", new Object[] { this.mob.getDisplayName() });
        }
        final CombatEntry ant2 = this.getMostSignificantFall();
        final CombatEntry ant3 = this.entries.get(this.entries.size() - 1);
        final Component mr5 = ant3.getAttackerName();
        final Entity aom6 = ant3.getSource().getEntity();
        Component mr7;
        if (ant2 != null && ant3.getSource() == DamageSource.FALL) {
            final Component mr6 = ant2.getAttackerName();
            if (ant2.getSource() == DamageSource.FALL || ant2.getSource() == DamageSource.OUT_OF_WORLD) {
                mr7 = new TranslatableComponent("death.fell.accident." + this.getFallLocation(ant2), new Object[] { this.mob.getDisplayName() });
            }
            else if (mr6 != null && (mr5 == null || !mr6.equals(mr5))) {
                final Entity aom7 = ant2.getSource().getEntity();
                final ItemStack bki9 = (aom7 instanceof LivingEntity) ? ((LivingEntity)aom7).getMainHandItem() : ItemStack.EMPTY;
                if (!bki9.isEmpty() && bki9.hasCustomHoverName()) {
                    mr7 = new TranslatableComponent("death.fell.assist.item", new Object[] { this.mob.getDisplayName(), mr6, bki9.getDisplayName() });
                }
                else {
                    mr7 = new TranslatableComponent("death.fell.assist", new Object[] { this.mob.getDisplayName(), mr6 });
                }
            }
            else if (mr5 != null) {
                final ItemStack bki10 = (aom6 instanceof LivingEntity) ? ((LivingEntity)aom6).getMainHandItem() : ItemStack.EMPTY;
                if (!bki10.isEmpty() && bki10.hasCustomHoverName()) {
                    mr7 = new TranslatableComponent("death.fell.finish.item", new Object[] { this.mob.getDisplayName(), mr5, bki10.getDisplayName() });
                }
                else {
                    mr7 = new TranslatableComponent("death.fell.finish", new Object[] { this.mob.getDisplayName(), mr5 });
                }
            }
            else {
                mr7 = new TranslatableComponent("death.fell.killer", new Object[] { this.mob.getDisplayName() });
            }
        }
        else {
            mr7 = ant3.getSource().getLocalizedDeathMessage(this.mob);
        }
        return mr7;
    }
    
    @Nullable
    public LivingEntity getKiller() {
        LivingEntity aoy2 = null;
        Player bec3 = null;
        float float4 = 0.0f;
        float float5 = 0.0f;
        for (final CombatEntry ant7 : this.entries) {
            if (ant7.getSource().getEntity() instanceof Player && (bec3 == null || ant7.getDamage() > float5)) {
                float5 = ant7.getDamage();
                bec3 = (Player)ant7.getSource().getEntity();
            }
            if (ant7.getSource().getEntity() instanceof LivingEntity && (aoy2 == null || ant7.getDamage() > float4)) {
                float4 = ant7.getDamage();
                aoy2 = (LivingEntity)ant7.getSource().getEntity();
            }
        }
        if (bec3 != null && float5 >= float4 / 3.0f) {
            return bec3;
        }
        return aoy2;
    }
    
    @Nullable
    private CombatEntry getMostSignificantFall() {
        CombatEntry ant2 = null;
        CombatEntry ant3 = null;
        float float4 = 0.0f;
        float float5 = 0.0f;
        for (int integer6 = 0; integer6 < this.entries.size(); ++integer6) {
            final CombatEntry ant4 = this.entries.get(integer6);
            final CombatEntry ant5 = (integer6 > 0) ? this.entries.get(integer6 - 1) : null;
            if ((ant4.getSource() == DamageSource.FALL || ant4.getSource() == DamageSource.OUT_OF_WORLD) && ant4.getFallDistance() > 0.0f && (ant2 == null || ant4.getFallDistance() > float5)) {
                if (integer6 > 0) {
                    ant2 = ant5;
                }
                else {
                    ant2 = ant4;
                }
                float5 = ant4.getFallDistance();
            }
            if (ant4.getLocation() != null && (ant3 == null || ant4.getDamage() > float4)) {
                ant3 = ant4;
                float4 = ant4.getDamage();
            }
        }
        if (float5 > 5.0f && ant2 != null) {
            return ant2;
        }
        if (float4 > 5.0f && ant3 != null) {
            return ant3;
        }
        return null;
    }
    
    private String getFallLocation(final CombatEntry ant) {
        return (ant.getLocation() == null) ? "generic" : ant.getLocation();
    }
    
    public int getCombatDuration() {
        if (this.inCombat) {
            return this.mob.tickCount - this.combatStartTime;
        }
        return this.combatEndTime - this.combatStartTime;
    }
    
    private void resetPreparedStatus() {
        this.nextLocation = null;
    }
    
    public void recheckStatus() {
        final int integer2 = this.inCombat ? 300 : 100;
        if (this.takingDamage && (!this.mob.isAlive() || this.mob.tickCount - this.lastDamageTime > integer2)) {
            final boolean boolean3 = this.inCombat;
            this.takingDamage = false;
            this.inCombat = false;
            this.combatEndTime = this.mob.tickCount;
            if (boolean3) {
                this.mob.onLeaveCombat();
            }
            this.entries.clear();
        }
    }
    
    public LivingEntity getMob() {
        return this.mob;
    }
}
