/*
 * © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
 */

package com.tiedup.remake.rig.anim;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.junit.jupiter.api.Test;

/**
 * Tests de {@link TiedUpLivingMotions} — verifie le nombre d'entries, l'unicite
 * des universalOrdinal() et l'absence de collision avec {@link LivingMotions}.
 *
 * Aucun MC runtime requis — les deux enums sont des enums Java purs partageant
 * le meme {@link LivingMotion#ENUM_MANAGER}. Le test force le class-load des
 * deux en appelant values() pour reproduire ce que TiedUpMod.commonSetup fait
 * a l'init mod.
 *
 * NOTE — ces tests n'exercent PAS le scenario prod ou LivingMotions pourrait
 * etre charge APRES TiedUpLivingMotions (ce qui ferait coller les ordinals
 * silencieusement). Cette garantie est assuree par :
 *   1. L'ordre explicite {@code LivingMotions.values()} puis
 *      {@code TiedUpLivingMotions.values()} dans
 *      {@code TiedUpMod.commonSetup} (review RISK-001).
 *   2. Le {@code synchronized} sur
 *      {@link com.tiedup.remake.rig.util.ExtendableEnumManager#assign} qui
 *      empeche la course si un autre mod class-load sa propre extension en
 *      parallele (review BUG-001).
 *
 * Un test JVM-fresh (ou l'ordre inverse est force via un ClassLoader isole)
 * serait possible mais pas rentable — le verrou est en prod, pas dans le test.
 */
class TiedUpLivingMotionsTest {

    /** L'enum doit contenir exactement 11 motions (8 design + 3 UX P0/P1). */
    @Test
    void values_has11Entries() {
        assertEquals(11, TiedUpLivingMotions.values().length,
            "TiedUpLivingMotions doit contenir 11 motions (8 design + 3 UX)");
    }

    /**
     * Chaque valeur doit avoir un universalOrdinal() unique a l'interieur de
     * l'enum. Garantit qu'il n'y a pas de collision dans
     * ExtendableEnumManager.assign() pour les motions TiedUp!.
     */
    @Test
    void allOrdinals_areUnique() {
        TiedUpLivingMotions[] values = TiedUpLivingMotions.values();
        long unique = Arrays.stream(values)
            .mapToInt(TiedUpLivingMotions::universalOrdinal)
            .distinct()
            .count();
        assertEquals(values.length, unique,
            "Chaque TiedUpLivingMotions doit avoir un universalOrdinal unique");
    }

    /**
     * Apres class-load des deux enums dans l'ordre {@code LivingMotions} puis
     * {@code TiedUpLivingMotions} (ordre force par {@code TiedUpMod.commonSetup}
     * en prod), aucune collision d'universalOrdinal ne doit exister entre les
     * deux. Ils partagent le meme ENUM_MANAGER, donc les ordinals sont
     * assignes a la suite sans doublon.
     *
     * ATTENTION : ce test force l'ordre correct (vanilla avant custom). Il ne
     * detecte donc PAS un scenario ou l'ordre serait inverse en prod — voir la
     * javadoc de classe pour les garanties externes (commonSetup + assign
     * synchronized).
     */
    @Test
    void ordinals_doNotCollideWithLivingMotionsVanilla_assumingCorrectLoadOrder() {
        // Force class-load des deux enums (idempotent — values() trigger static init)
        LivingMotions[] vanilla = LivingMotions.values();
        TiedUpLivingMotions[] custom = TiedUpLivingMotions.values();

        Set<Integer> allOrdinals = new HashSet<>();
        for (LivingMotions m : vanilla) {
            allOrdinals.add(m.universalOrdinal());
        }
        for (TiedUpLivingMotions m : custom) {
            boolean added = allOrdinals.add(m.universalOrdinal());
            if (!added) {
                throw new AssertionError(
                    "Collision universalOrdinal: TiedUpLivingMotions." + m.name()
                        + " (ordinal=" + m.universalOrdinal()
                        + ") collide avec une entree de LivingMotions"
                );
            }
        }

        assertEquals(vanilla.length + custom.length, allOrdinals.size(),
            "La somme des ordinals distincts doit egaler vanilla.length + custom.length");
    }
}
