package dev.lions.unionflow.server.entity;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Permission")
class PermissionTest {

    @Test
    @DisplayName("getters/setters")
    void gettersSetters() {
        Permission p = new Permission();
        p.setCode("ORG > MEMBRE > CREATE");
        p.setModule("ORG");
        p.setRessource("MEMBRE");
        p.setAction("CREATE");
        p.setLibelle("Créer un membre");
        p.setDescription("Permission de création");

        assertThat(p.getCode()).isEqualTo("ORG > MEMBRE > CREATE");
        assertThat(p.getModule()).isEqualTo("ORG");
        assertThat(p.getRessource()).isEqualTo("MEMBRE");
        assertThat(p.getAction()).isEqualTo("CREATE");
    }

    @Test
    @DisplayName("genererCode")
    void genererCode() {
        String code = Permission.genererCode("org", "membre", "create");
        assertThat(code).isEqualTo("ORG > MEMBRE > CREATE");
    }

    @Test
    @DisplayName("isCodeValide")
    void isCodeValide() {
        Permission p = new Permission();
        p.setCode("A > B > C");
        assertThat(p.isCodeValide()).isTrue();
        p.setCode("invalid");
        assertThat(p.isCodeValide()).isFalse();
    }

    @Test
    @DisplayName("isCodeValide: false si code null")
    void isCodeValide_null() {
        Permission p = new Permission();
        p.setCode(null);
        assertThat(p.isCodeValide()).isFalse();
    }

    @Test
    @DisplayName("isCodeValide: false si contient ' > ' mais moins de 3 parties")
    void isCodeValide_twoPartsOnly() {
        Permission p = new Permission();
        p.setCode("A > B");
        assertThat(p.isCodeValide()).isFalse();
    }

    @Test
    @DisplayName("onCreate: code null + module/ressource/action renseignés → code généré")
    void onCreate_generatesCode_whenNullAndComponentsPresent() throws Exception {
        Permission p = new Permission();
        p.setCode(null);
        p.setModule("org");
        p.setRessource("membre");
        p.setAction("create");
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isEqualTo("ORG > MEMBRE > CREATE");
    }

    @Test
    @DisplayName("onCreate: code null + composants null → code reste null")
    void onCreate_codeRemainsNull_whenComponentsNull() throws Exception {
        Permission p = new Permission();
        p.setCode(null);
        p.setModule(null);
        p.setRessource(null);
        p.setAction(null);
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isNull();
    }

    @Test
    @DisplayName("onCreate: code déjà renseigné → non écrasé")
    void onCreate_existingCode_notOverwritten() throws Exception {
        Permission p = new Permission();
        p.setCode("X > Y > Z");
        p.setModule("other");
        p.setRessource("other");
        p.setAction("other");
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isEqualTo("X > Y > Z");
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        Permission a = new Permission();
        a.setId(id);
        a.setCode("X > Y > Z");
        a.setModule("X");
        a.setRessource("Y");
        a.setAction("Z");
        Permission b = new Permission();
        b.setId(id);
        b.setCode("X > Y > Z");
        b.setModule("X");
        b.setRessource("Y");
        b.setAction("Z");
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        Permission p = new Permission();
        p.setCode("X > Y > Z");
        p.setModule("X");
        p.setRessource("Y");
        p.setAction("Z");
        assertThat(p.toString()).isNotNull().isNotEmpty();
    }

    // ── Branch coverage manquantes ─────────────────────────────────────────

    /**
     * L85 branch manquante : code = "" (not null but isEmpty → true) avec composants présents
     * → couvre la branche `code != null && code.isEmpty()` (deuxième branche du ||)
     */
    @Test
    @DisplayName("onCreate: code vide (empty) + composants présents → code généré (branche isEmpty)")
    void onCreate_emptyCode_withComponents_generatesCode() throws Exception {
        Permission p = new Permission();
        p.setCode("");
        p.setModule("org");
        p.setRessource("membre");
        p.setAction("read");
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isEqualTo("ORG > MEMBRE > READ");
    }

    /**
     * L86 branch manquante : module != null, ressource != null, action == null
     * → la condition `module != null && ressource != null && action != null` est false (action null)
     * → code reste null
     */
    @Test
    @DisplayName("onCreate: module et ressource présents, action null → code reste null (branche action null)")
    void onCreate_moduleAndRessourcePresent_actionNull_codeRemainsNull() throws Exception {
        Permission p = new Permission();
        p.setCode(null);
        p.setModule("org");
        p.setRessource("membre");
        p.setAction(null);
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isNull();
    }

    /**
     * L86 branch manquante : module != null, ressource == null
     * → la condition `module != null && ressource != null && action != null` est false (ressource null)
     */
    @Test
    @DisplayName("onCreate: module présent, ressource null → code reste null (branche ressource null)")
    void onCreate_modulePresent_ressourceNull_codeRemainsNull() throws Exception {
        Permission p = new Permission();
        p.setCode(null);
        p.setModule("org");
        p.setRessource(null);
        p.setAction("create");
        Method onCreate = Permission.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(p);
        assertThat(p.getCode()).isNull();
    }
}
