package dev.lions.unionflow.server.entity;

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

import java.math.BigDecimal;
import java.util.UUID;

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

@DisplayName("Adresse")
class AdresseTest {

    @Test
    @DisplayName("constructeur par défaut et getters/setters")
    void constructeurEtGettersSetters() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setAdresse("1 rue Test");
        a.setComplementAdresse("Bât A");
        a.setCodePostal("75001");
        a.setVille("Paris");
        a.setRegion("Île-de-France");
        a.setPays("France");
        a.setLatitude(new BigDecimal("48.8566"));
        a.setLongitude(new BigDecimal("2.3522"));
        a.setPrincipale(true);
        a.setLibelle("Siège social");
        a.setNotes("Notes");

        assertThat(a.getTypeAdresse()).isEqualTo("SIEGE");
        assertThat(a.getAdresse()).isEqualTo("1 rue Test");
        assertThat(a.getComplementAdresse()).isEqualTo("Bât A");
        assertThat(a.getCodePostal()).isEqualTo("75001");
        assertThat(a.getVille()).isEqualTo("Paris");
        assertThat(a.getRegion()).isEqualTo("Île-de-France");
        assertThat(a.getPays()).isEqualTo("France");
        assertThat(a.getLatitude()).isEqualByComparingTo("48.8566");
        assertThat(a.getLongitude()).isEqualByComparingTo("2.3522");
        assertThat(a.getPrincipale()).isTrue();
        assertThat(a.getLibelle()).isEqualTo("Siège social");
        assertThat(a.getNotes()).isEqualTo("Notes");
    }

    @Test
    @DisplayName("getAdresseComplete: concatène tous les champs non vides")
    void getAdresseComplete() {
        Adresse a = Adresse.builder()
                .typeAdresse("SIEGE")
                .adresse("1 rue Test")
                .complementAdresse("Bât A")
                .codePostal("75001")
                .ville("Paris")
                .region("IDF")
                .pays("France")
                .build();
        assertThat(a.getAdresseComplete()).contains("1 rue Test", "Bât A", "75001", "Paris", "IDF", "France");
    }

    @Test
    @DisplayName("getAdresseComplete: retourne chaîne vide quand tout null")
    void getAdresseComplete_vide() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        assertThat(a.getAdresseComplete()).isEmpty();
    }

    @Test
    @DisplayName("getAdresseComplete: un seul champ")
    void getAdresseComplete_unChamp() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setVille("Lyon");
        assertThat(a.getAdresseComplete()).isEqualTo("Lyon");
    }

    @Test
    @DisplayName("hasCoordinates: true si latitude et longitude renseignées")
    void hasCoordinates_true() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setLatitude(new BigDecimal("48.0"));
        a.setLongitude(new BigDecimal("2.0"));
        assertThat(a.hasCoordinates()).isTrue();
    }

    @Test
    @DisplayName("hasCoordinates: false si un champ null")
    void hasCoordinates_false() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        assertThat(a.hasCoordinates()).isFalse();
        a.setLatitude(new BigDecimal("48.0"));
        assertThat(a.hasCoordinates()).isFalse();
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        Adresse a = new Adresse();
        a.setId(id);
        a.setTypeAdresse("SIEGE");
        Adresse b = new Adresse();
        b.setId(id);
        b.setTypeAdresse("SIEGE");
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
        assertThat(a).isNotEqualTo(null);
        assertThat(a).isNotEqualTo("x");
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        assertThat(a.toString()).isNotNull().isNotEmpty();
    }

    // ── Branch coverage: getAdresseComplete ────────────────────────────────

    @Test
    @DisplayName("getAdresseComplete: only complementAdresse (sb empty at append)")
    void getAdresseComplete_onlyComplementAdresse() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setComplementAdresse("Bât B");
        assertThat(a.getAdresseComplete()).isEqualTo("Bât B");
    }

    @Test
    @DisplayName("getAdresseComplete: only codePostal (sb empty at append)")
    void getAdresseComplete_onlyCodePostal() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setCodePostal("75002");
        assertThat(a.getAdresseComplete()).isEqualTo("75002");
    }

    @Test
    @DisplayName("getAdresseComplete: only region (sb empty at append)")
    void getAdresseComplete_onlyRegion() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setRegion("Bretagne");
        assertThat(a.getAdresseComplete()).isEqualTo("Bretagne");
    }

    @Test
    @DisplayName("getAdresseComplete: only pays (sb empty at append)")
    void getAdresseComplete_onlyPays() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setPays("France");
        assertThat(a.getAdresseComplete()).isEqualTo("France");
    }

    @Test
    @DisplayName("getAdresseComplete: adresse + codePostal (skip complementAdresse), triggers sb>0 for codePostal")
    void getAdresseComplete_adresseAndCodePostal() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setAdresse("2 rue X");
        a.setCodePostal("13000");
        assertThat(a.getAdresseComplete()).isEqualTo("2 rue X, 13000");
    }

    @Test
    @DisplayName("getAdresseComplete: codePostal + ville (sb>0 for ville space separator)")
    void getAdresseComplete_codePostalAndVille() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setCodePostal("69001");
        a.setVille("Lyon");
        assertThat(a.getAdresseComplete()).isEqualTo("69001 Lyon");
    }

    @Test
    @DisplayName("getAdresseComplete: adresse with empty string fields ignored")
    void getAdresseComplete_emptyStringFieldsIgnored() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setAdresse("3 rue Y");
        a.setComplementAdresse("");
        a.setCodePostal("");
        a.setVille("");
        a.setRegion("");
        a.setPays("");
        assertThat(a.getAdresseComplete()).isEqualTo("3 rue Y");
    }

    // ── Branch coverage manquante ──────────────────────────────────────────

    /**
     * L107 branch manquante : adresse != null mais adresse.isEmpty() → false (deuxième branche du &&)
     * → `if (adresse != null && !adresse.isEmpty())` → false (adresse est vide "")
     */
    @Test
    @DisplayName("getAdresseComplete: adresse = empty string (non null) → ignorée (branche isEmpty)")
    void getAdresseComplete_adresseEmptyString_ignored() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        a.setAdresse(""); // non null mais vide → condition !adresse.isEmpty() est false → ignorée
        a.setVille("Dakar");
        assertThat(a.getAdresseComplete()).isEqualTo("Dakar");
    }

    @Test
    @DisplayName("relations: organisation, membre, evenement")
    void relations() {
        Adresse a = new Adresse();
        a.setTypeAdresse("SIEGE");
        Organisation o = new Organisation();
        Membre m = new Membre();
        Evenement e = new Evenement();
        a.setOrganisation(o);
        a.setMembre(m);
        a.setEvenement(e);
        assertThat(a.getOrganisation()).isSameAs(o);
        assertThat(a.getMembre()).isSameAs(m);
        assertThat(a.getEvenement()).isSameAs(e);
    }
}
