/*
 * 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.patch;

import net.minecraft.world.entity.player.Player;

import com.tiedup.remake.rig.TiedUpAnimationRegistry;
import com.tiedup.remake.rig.TiedUpArmatures;
import com.tiedup.remake.rig.TiedUpRigRegistry;
import com.tiedup.remake.rig.anim.Animator;
import com.tiedup.remake.rig.anim.LivingMotions;
import com.tiedup.remake.rig.anim.types.StaticAnimation;
import com.tiedup.remake.rig.armature.HumanoidArmature;
import com.tiedup.remake.rig.math.MathUtils;
import com.tiedup.remake.rig.math.OpenMatrix4f;

/**
 * RIG Phase 2.4 — patch de capability attaché à un {@link Player}.
 *
 * <p>Étoffé à partir du stub Phase 0 pour :</p>
 * <ul>
 *   <li>Fournir l'{@link #getArmature() armature biped} TiedUp
 *       ({@link TiedUpArmatures#BIPED})</li>
 *   <li>Activer le rendering RIG patched ({@link #overrideRender()} = true)
 *       — {@link ServerPlayerPatch} ré-override à false et
 *       {@link LocalPlayerPatch} gère le cas first-person</li>
 *   <li>Fournir un {@link #getModelMatrix(float)} avec scale player vanilla
 *       ({@value #PLAYER_SCALE}) — cf. EF {@code PlayerPatch:82,176}</li>
 *   <li>Stub {@link #initAnimator(Animator)} qui bind
 *       {@code LivingMotions.IDLE → EMPTY_ANIMATION} (Phase 2.7 remplacera par
 *       {@code CONTEXT_STAND_IDLE} co-authored)</li>
 * </ul>
 *
 * <p><b>Ce qui manque vs EF PlayerPatch (766 LOC)</b>, voulu :</p>
 * <ul>
 *   <li>Stamina system ({@code STAMINA} EntityDataAccessor + regen logic)</li>
 *   <li>PlayerMode VANILLA/EPICFIGHT toggle</li>
 *   <li>modelYRot sync / turningLocked handling</li>
 *   <li>xo/yo/zo previous pos caching</li>
 *   <li>PlayerEventListener — remplacé par SystemMessageManager/events TiedUp</li>
 *   <li>Skill system entièrement</li>
 *   <li>Toute la logique attaque / damage / offhand / armor negation</li>
 * </ul>
 *
 * <p>TiedUp n'a pas de combat — ces features seraient dead code. Si on en
 * veut une (ex. stamina pour struggle), on l'ajoutera au cas par cas (D-04).</p>
 */
public abstract class PlayerPatch<T extends Player> extends LivingEntityPatch<T> {

    /**
     * Scale vanilla player EF-identique (15/16 ≈ 0.9375). Le modèle vanilla
     * Minecraft rend le joueur à 15/16 de sa taille logique — si on ne
     * compense pas, le skinned mesh apparaît "trop grand" comparé à la hitbox.
     *
     * <p>Source : EF {@code PlayerPatch:82}.</p>
     */
    protected static final float PLAYER_SCALE = 15.0F / 16.0F;

    /**
     * Override — stub sans transition / sans vélocité.
     *
     * <p>Phase 2.7+ implémentera la détection de motion (walk/run/sneak/sit/
     * swim/kneel pour TiedUp) via vélocité + state checks. Ici on ne fait
     * rien pour que les {@link #currentLivingMotion} restent à IDLE par
     * défaut (cf. {@link LivingEntityPatch}).</p>
     *
     * @param considerInaction paramètre EF legacy — si true, l'impl complète
     *                         doit bloquer la transition de motion si l'entité
     *                         est dans une {@code inaction()}. Pas utilisé ici.
     */
    @Override
    public void updateMotion(boolean considerInaction) {
        // Stub Phase 2.4 — pas de motion detection.
        // Phase 2.7 : cf. EF LivingEntityPatch.updateMotion (velocity + state
        // machine) + mapping sur LivingMotions TiedUp (idle/walk/kneel/sit).
    }

    /**
     * Retourne l'armature biped TiedUp — identique pour tous les players.
     *
     * <p>Phase 2.4 : version procédurale ({@link TiedUpArmatures#BIPED}
     * construit from scratch). Phase 2.7 remplacera par un chargement JSON
     * avec offsets Blender-authored.</p>
     *
     * <p>Pattern EF :
     * {@code AbstractClientPlayerPatch.java:~70} expose {@code this.armature}
     * initialisé au constructor. On renvoie directement le singleton — léger
     * et thread-safe (construction lazy dans {@link TiedUpArmatures#BIPED}).</p>
     */
    @Override
    public HumanoidArmature getArmature() {
        return TiedUpArmatures.BIPED.get();
    }

    /**
     * Override — tous les players passent par le renderer RIG patched.
     *
     * <p>{@link ServerPlayerPatch} ré-override à false (le serveur ne rend
     * rien). {@link LocalPlayerPatch} ré-override pour gérer le cas
     * first-person (cf. doc là-bas).</p>
     */
    @Override
    public boolean overrideRender() {
        return true;
    }

    /**
     * Model matrix pour le render : position identity (le renderer applique
     * déjà la translation) + rotation yaw (le corps suit la caméra) + scale
     * {@value #PLAYER_SCALE}.
     *
     * <p>Simplifié vs EF : pas de handling {@code modelYRot} (self-managed
     * rotation lerp pour turning lock) et pas de {@code ridingEntity} override
     * — Phase 2.7+ si on ajoute un système de mount TiedUp (maid pet sitting
     * etc.).</p>
     *
     * <p>Baby support (half scale) — EF applique 0.5 si {@code isBaby}. On
     * garde pour cohérence (les NPCs Damsel n'ont pas d'état baby mais
     * VillagerMCA si un jour on les patch le veut).</p>
     */
    @Override
    public OpenMatrix4f getModelMatrix(float partialTick) {
        float scale = (this.original.isBaby() ? 0.5F : 1.0F) * PLAYER_SCALE;

        // Signature : xPosO, xPos, yPosO, yPos, zPosO, zPos, xRotO, xRot,
        //             yRotO, yRot, partialTick, scaleX, scaleY, scaleZ
        // On ignore pos/xRot (delta pose) — l'entity renderer applique déjà
        // la position monde. Seul le yRot (yaw corps, pas tête) est utile
        // pour que le mesh s'oriente avec l'entity.
        return MathUtils.getModelMatrixIntegral(
            0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F,
            0.0F, 0.0F,
            this.original.yBodyRotO, this.original.yBodyRot,
            partialTick, scale, scale, scale
        );
    }

    /**
     * Hook {@link LivingEntityPatch#initAnimator(Animator)} : bind la motion
     * IDLE sur l'animation "ne fait rien" par défaut. Phase 2.7 remplacera
     * par {@code TiedUpAnimationRegistry.CONTEXT_STAND_IDLE} avec quelques
     * keyframes de balancement.
     *
     * <p>L'ordre EF ajoute ~25 motions différentes (WALK, RUN, SNEAK, SIT,
     * SLEEP, etc.). On se limite à IDLE Phase 2.4 — ajouter les autres
     * sans anim source = pollution registre pour rien. Au fur et à mesure
     * que les JSON co-authored arrivent (Phase 2.7 / 4), on ajoute les
     * binds correspondants.</p>
     */
    @Override
    protected void initAnimator(Animator animator) {
        super.initAnimator(animator);
        // Phase 2.7 : si le registry a init, on bind sur CONTEXT_STAND_IDLE
        // (placeholder procédural 2-keyframes identity — voir
        // TiedUpAnimationRegistry + ASSETS_NEEDED.md §2). Sinon fallback sur
        // EMPTY_ANIMATION — peut arriver si le patch est construit avant que
        // FMLCommonSetupEvent n'ait tourné (rare mais pas impossible en dev).
        StaticAnimation idle = TiedUpAnimationRegistry.CONTEXT_STAND_IDLE;
        animator.addLivingAnimation(
            LivingMotions.IDLE,
            idle != null ? idle.getAccessor() : TiedUpRigRegistry.EMPTY_ANIMATION
        );
    }

}
