/*
 * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
 * by the Epic Fight Team, licensed under GPLv3.
 * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
 */

package com.tiedup.remake.rig.render;

import com.mojang.blaze3d.vertex.PoseStack;

import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderNameTagEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Event.Result;

import com.tiedup.remake.rig.anim.Pose;
import com.tiedup.remake.rig.armature.Armature;
import com.tiedup.remake.rig.asset.AssetAccessor;
import com.tiedup.remake.rig.math.MathUtils;
import com.tiedup.remake.rig.math.OpenMatrix4f;
import com.tiedup.remake.rig.math.QuaternionUtils;
import com.tiedup.remake.rig.mesh.SkinnedMesh;
import com.tiedup.remake.rig.mixin.client.MixinEntityRenderer;
import com.tiedup.remake.rig.patch.LivingEntityPatch;

/**
 * Base abstraite du pipeline de rendu RIG patché — remplace l'{@link EntityRenderer}
 * vanilla pour les entités dont le patch retourne {@code overrideRender() == true}.
 *
 * <p>Fournit trois responsabilités :</p>
 * <ol>
 *   <li>Render nameplate (via {@link RenderNameTagEvent} Forge + mixin invoker)</li>
 *   <li>Application de la model matrix entité (rotation 180° + yaw corps) au {@link PoseStack}</li>
 *   <li>Baking de la pose courante sur l'{@link Armature} (pour que
 *       {@code armature.getPoseMatrices()} soit à jour avant le draw du mesh)</li>
 * </ol>
 *
 * <p>Fork verbatim de {@code yesman.epicfight.client.renderer.patched.entity.PatchedEntityRenderer}
 * (EF 62 LOC). Imports rewrités vers les packages RIG TiedUp.</p>
 *
 * @param <E>  entité vivante ({@code LivingEntity}+)
 * @param <T>  patch RIG associé
 * @param <R>  renderer vanilla ({@code EntityRenderer<E>})
 * @param <AM> mesh skinné dérivé
 */
@OnlyIn(Dist.CLIENT)
public abstract class PatchedEntityRenderer<E extends LivingEntity, T extends LivingEntityPatch<E>, R extends EntityRenderer<E>, AM extends SkinnedMesh> {

	public void render(E entity, T entitypatch, R renderer, MultiBufferSource buffer, PoseStack poseStack, int packedLight, float partialTicks) {
		RenderNameTagEvent renderNameplateEvent = new RenderNameTagEvent(entity, entity.getDisplayName(), renderer, poseStack, buffer, packedLight, partialTicks);
		MinecraftForge.EVENT_BUS.post(renderNameplateEvent);

		MixinEntityRenderer entityRendererAccessor = (MixinEntityRenderer) renderer;

		if ((entityRendererAccessor.invokeShouldShowName(entity) || renderNameplateEvent.getResult() == Result.ALLOW) && renderNameplateEvent.getResult() != Result.DENY) {
			entityRendererAccessor.invokeRenderNameTag(entity, renderNameplateEvent.getContent(), poseStack, buffer, packedLight);
		}
	}

	public void mulPoseStack(PoseStack poseStack, Armature armature, E entity, T entitypatch, float partialTicks) {
		OpenMatrix4f modelMatrix = entitypatch.getModelMatrix(partialTicks);
		poseStack.mulPose(QuaternionUtils.YP.rotationDegrees(180.0F));
		MathUtils.mulStack(poseStack, modelMatrix);

		if (LivingEntityRenderer.isEntityUpsideDown(entity)) {
			poseStack.translate(0.0D, entity.getBbHeight() + 0.1F, 0.0D);
			poseStack.mulPose(QuaternionUtils.ZP.rotationDegrees(180.0F));
		}
	}

	public void setArmaturePose(T entitypatch, Armature armature, float partialTicks) {
		Pose pose = entitypatch.getAnimator().getPose(partialTicks);
		this.setJointTransforms(entitypatch, armature, pose, partialTicks);
		armature.setPose(pose);
	}

	public AssetAccessor<AM> getMeshProvider(T entitypatch) {
		return this.getDefaultMesh();
	}

	public abstract AssetAccessor<AM> getDefaultMesh();

	/**
	 * Override pour modifier la pose juste avant le bake (ex. scale de la tête
	 * pour les babies). <b>Developers shouldn't implement any interpolations in
	 * this method</b> — utilise {@link LivingEntityPatch#poseTick} à la place.
	 */
	public void setJointTransforms(T entitypatch, Armature armature, Pose pose, float partialTicks) {
	}
}
