package net.minecraft.client.renderer.entity;

import org.apache.logging.log4j.LogManager;
import net.minecraft.world.scores.Team;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.player.PlayerModelPart;
import net.minecraft.ChatFormatting;
import com.mojang.math.Vector3f;
import net.minecraft.client.renderer.texture.OverlayTexture;
import javax.annotation.Nullable;
import net.minecraft.resources.ResourceLocation;
import java.util.Iterator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Pose;
import net.minecraft.util.Mth;
import net.minecraft.client.renderer.MultiBufferSource;
import com.mojang.blaze3d.vertex.PoseStack;
import com.google.common.collect.Lists;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import java.util.List;
import org.apache.logging.log4j.Logger;
import net.minecraft.client.model.EntityModel;
import net.minecraft.world.entity.LivingEntity;

public abstract class LivingEntityRenderer<T extends LivingEntity, M extends EntityModel<T>> extends EntityRenderer<T> implements RenderLayerParent<T, M> {
    private static final Logger LOGGER;
    protected M model;
    protected final List<RenderLayer<T, M>> layers;
    
    public LivingEntityRenderer(final EntityRenderDispatcher egm, final M dvv, final float float3) {
        super(egm);
        this.layers = Lists.newArrayList();
        this.model = dvv;
        this.shadowRadius = float3;
    }
    
    protected final boolean addLayer(final RenderLayer<T, M> ekm) {
        return this.layers.add(ekm);
    }
    
    @Override
    public M getModel() {
        return this.model;
    }
    
    @Override
    public void render(final T aoy, final float float2, final float float3, final PoseStack dhl, final MultiBufferSource ebz, final int integer) {
        dhl.pushPose();
        this.model.attackTime = this.getAttackAnim(aoy, float3);
        this.model.riding = aoy.isPassenger();
        this.model.young = aoy.isBaby();
        float float4 = Mth.rotLerp(float3, aoy.yBodyRotO, aoy.yBodyRot);
        final float float5 = Mth.rotLerp(float3, aoy.yHeadRotO, aoy.yHeadRot);
        float float6 = float5 - float4;
        if (aoy.isPassenger() && aoy.getVehicle() instanceof LivingEntity) {
            final LivingEntity aoy2 = (LivingEntity)aoy.getVehicle();
            float4 = Mth.rotLerp(float3, aoy2.yBodyRotO, aoy2.yBodyRot);
            float6 = float5 - float4;
            float float7 = Mth.wrapDegrees(float6);
            if (float7 < -85.0f) {
                float7 = -85.0f;
            }
            if (float7 >= 85.0f) {
                float7 = 85.0f;
            }
            float4 = float5 - float7;
            if (float7 * float7 > 2500.0f) {
                float4 += float7 * 0.2f;
            }
            float6 = float5 - float4;
        }
        final float float8 = Mth.lerp(float3, aoy.xRotO, aoy.xRot);
        if (aoy.getPose() == Pose.SLEEPING) {
            final Direction fz12 = aoy.getBedOrientation();
            if (fz12 != null) {
                final float float9 = aoy.getEyeHeight(Pose.STANDING) - 0.1f;
                dhl.translate(-fz12.getStepX() * float9, 0.0, -fz12.getStepZ() * float9);
            }
        }
        float float7 = this.getBob(aoy, float3);
        this.setupRotations(aoy, dhl, float7, float4, float3);
        dhl.scale(-1.0f, -1.0f, 1.0f);
        this.scale(aoy, dhl, float3);
        dhl.translate(0.0, -1.5010000467300415, 0.0);
        float float9 = 0.0f;
        float float10 = 0.0f;
        if (!aoy.isPassenger() && aoy.isAlive()) {
            float9 = Mth.lerp(float3, aoy.animationSpeedOld, aoy.animationSpeed);
            float10 = aoy.animationPosition - aoy.animationSpeed * (1.0f - float3);
            if (aoy.isBaby()) {
                float10 *= 3.0f;
            }
            if (float9 > 1.0f) {
                float9 = 1.0f;
            }
        }
        this.model.prepareMobModel(aoy, float10, float9, float3);
        this.model.setupAnim(aoy, float10, float9, float7, float6, float8);
        final Minecraft dlx15 = Minecraft.getInstance();
        final boolean boolean16 = this.isBodyVisible(aoy);
        final boolean boolean17 = !boolean16 && !aoy.isInvisibleTo(dlx15.player);
        final boolean boolean18 = dlx15.shouldEntityAppearGlowing(aoy);
        final RenderType ech19 = this.getRenderType(aoy, boolean16, boolean17, boolean18);
        if (ech19 != null) {
            final VertexConsumer dhp20 = ebz.getBuffer(ech19);
            final int integer2 = getOverlayCoords(aoy, this.getWhiteOverlayProgress(aoy, float3));
            this.model.renderToBuffer(dhl, dhp20, integer, integer2, 1.0f, 1.0f, 1.0f, boolean17 ? 0.15f : 1.0f);
        }
        if (!aoy.isSpectator()) {
            for (final RenderLayer<T, M> ekm21 : this.layers) {
                ekm21.render(dhl, ebz, integer, aoy, float10, float9, float3, float7, float6, float8);
            }
        }
        dhl.popPose();
        super.render(aoy, float2, float3, dhl, ebz, integer);
    }
    
    @Nullable
    protected RenderType getRenderType(final T aoy, final boolean boolean2, final boolean boolean3, final boolean boolean4) {
        final ResourceLocation uh6 = this.getTextureLocation(aoy);
        if (boolean3) {
            return RenderType.itemEntityTranslucentCull(uh6);
        }
        if (boolean2) {
            return this.model.renderType(uh6);
        }
        if (boolean4) {
            return RenderType.outline(uh6);
        }
        return null;
    }
    
    public static int getOverlayCoords(final LivingEntity aoy, final float float2) {
        return OverlayTexture.pack(OverlayTexture.u(float2), OverlayTexture.v(aoy.hurtTime > 0 || aoy.deathTime > 0));
    }
    
    protected boolean isBodyVisible(final T aoy) {
        return !aoy.isInvisible();
    }
    
    private static float sleepDirectionToRotation(final Direction fz) {
        switch (fz) {
            case SOUTH: {
                return 90.0f;
            }
            case WEST: {
                return 0.0f;
            }
            case NORTH: {
                return 270.0f;
            }
            case EAST: {
                return 180.0f;
            }
            default: {
                return 0.0f;
            }
        }
    }
    
    protected boolean isShaking(final T aoy) {
        return false;
    }
    
    protected void setupRotations(final T aoy, final PoseStack dhl, final float float3, float float4, final float float5) {
        if (this.isShaking(aoy)) {
            float4 += (float)(Math.cos(aoy.tickCount * 3.25) * 3.141592653589793 * 0.4000000059604645);
        }
        final Pose apj7 = aoy.getPose();
        if (apj7 != Pose.SLEEPING) {
            dhl.mulPose(Vector3f.YP.rotationDegrees(180.0f - float4));
        }
        if (aoy.deathTime > 0) {
            float float6 = (aoy.deathTime + float5 - 1.0f) / 20.0f * 1.6f;
            float6 = Mth.sqrt(float6);
            if (float6 > 1.0f) {
                float6 = 1.0f;
            }
            dhl.mulPose(Vector3f.ZP.rotationDegrees(float6 * this.getFlipDegrees(aoy)));
        }
        else if (aoy.isAutoSpinAttack()) {
            dhl.mulPose(Vector3f.XP.rotationDegrees(-90.0f - aoy.xRot));
            dhl.mulPose(Vector3f.YP.rotationDegrees((aoy.tickCount + float5) * -75.0f));
        }
        else if (apj7 == Pose.SLEEPING) {
            final Direction fz8 = aoy.getBedOrientation();
            final float float7 = (fz8 != null) ? sleepDirectionToRotation(fz8) : float4;
            dhl.mulPose(Vector3f.YP.rotationDegrees(float7));
            dhl.mulPose(Vector3f.ZP.rotationDegrees(this.getFlipDegrees(aoy)));
            dhl.mulPose(Vector3f.YP.rotationDegrees(270.0f));
        }
        else if (aoy.hasCustomName() || aoy instanceof Player) {
            final String string8 = ChatFormatting.stripFormatting(aoy.getName().getString());
            if (("Dinnerbone".equals(string8) || "Grumm".equals(string8)) && (!(aoy instanceof Player) || ((Player)aoy).isModelPartShown(PlayerModelPart.CAPE))) {
                dhl.translate(0.0, aoy.getBbHeight() + 0.1f, 0.0);
                dhl.mulPose(Vector3f.ZP.rotationDegrees(180.0f));
            }
        }
    }
    
    protected float getAttackAnim(final T aoy, final float float2) {
        return aoy.getAttackAnim(float2);
    }
    
    protected float getBob(final T aoy, final float float2) {
        return aoy.tickCount + float2;
    }
    
    protected float getFlipDegrees(final T aoy) {
        return 90.0f;
    }
    
    protected float getWhiteOverlayProgress(final T aoy, final float float2) {
        return 0.0f;
    }
    
    protected void scale(final T aoy, final PoseStack dhl, final float float3) {
    }
    
    @Override
    protected boolean shouldShowName(final T aoy) {
        final double double3 = this.entityRenderDispatcher.distanceToSqr(aoy);
        final float float5 = aoy.isDiscrete() ? 32.0f : 64.0f;
        if (double3 >= float5 * float5) {
            return false;
        }
        final Minecraft dlx6 = Minecraft.getInstance();
        final LocalPlayer ebf7 = dlx6.player;
        final boolean boolean8 = !aoy.isInvisibleTo(ebf7);
        if (aoy != ebf7) {
            final Team dfo9 = aoy.getTeam();
            final Team dfo10 = ebf7.getTeam();
            if (dfo9 != null) {
                final Team.Visibility b11 = dfo9.getNameTagVisibility();
                switch (b11) {
                    case ALWAYS: {
                        return boolean8;
                    }
                    case NEVER: {
                        return false;
                    }
                    case HIDE_FOR_OTHER_TEAMS: {
                        return (dfo10 == null) ? boolean8 : (dfo9.isAlliedTo(dfo10) && (dfo9.canSeeFriendlyInvisibles() || boolean8));
                    }
                    case HIDE_FOR_OWN_TEAM: {
                        return (dfo10 == null) ? boolean8 : (!dfo9.isAlliedTo(dfo10) && boolean8);
                    }
                    default: {
                        return true;
                    }
                }
            }
        }
        return Minecraft.renderNames() && aoy != dlx6.getCameraEntity() && boolean8 && !aoy.isVehicle();
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
