package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.notNullValue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

import dev.lions.unionflow.server.api.dto.organisation.request.CreateOrganisationRequest;
import dev.lions.unionflow.server.api.dto.organisation.request.UpdateOrganisationRequest;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.service.KeycloakService;
import dev.lions.unionflow.server.service.OrganisationService;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.ws.rs.NotFoundException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class OrganisationResourceMockTest {

    @InjectMock
    OrganisationService organisationService;

    @InjectMock
    KeycloakService keycloakService;

    // ============================================================
    // listerMesOrganisations — GET /mes
    // ============================================================

    @Test
    @TestSecurity(user = "orgadmin@test.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /api/organisations/mes retourne 200 avec liste des organisations de l'utilisateur")
    void listerMesOrganisations_returns200() {
        Organisation org = new Organisation();
        org.setId(UUID.randomUUID());
        org.setNom("Mon Association");
        org.setActif(true);

        OrganisationResponse response = new OrganisationResponse();
        response.setId(org.getId());
        response.setNom("Mon Association");

        when(organisationService.listerOrganisationsPourUtilisateur(any())).thenReturn(List.of(org));
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        given()
                .when()
                .get("/api/organisations/mes")
                .then()
                .statusCode(200)
                .body("$", notNullValue());
    }

    @Test
    @TestSecurity(user = "orgadmin@test.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /api/organisations/mes retourne 200 avec liste vide")
    void listerMesOrganisations_empty_returns200() {
        when(organisationService.listerOrganisationsPourUtilisateur(any())).thenReturn(List.of());

        given()
                .when()
                .get("/api/organisations/mes")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = " ", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /api/organisations/mes retourne 200 avec liste vide quand email est blanc")
    void listerMesOrganisations_blankEmail_returnsEmptyList() {
        given()
                .when()
                .get("/api/organisations/mes")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // listerOrganisations — GET / (chemin normal)
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations retourne 200 avec liste paginée (ADMIN)")
    void listerOrganisations_admin_returns200() {
        when(organisationService.listerOrganisationsActives(anyInt(), anyInt())).thenReturn(List.of());
        when(organisationService.compterOrganisationsActives()).thenReturn(0L);
        when(organisationService.convertToSummaryResponse(any(Organisation.class)))
                .thenReturn(new OrganisationSummaryResponse(null, null, null, null, null, null, null, null, null, null, null, null));

        given()
                .queryParam("page", 0)
                .queryParam("size", 20)
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200)
                .body(notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations retourne 200 avec pagination personnalisée")
    void listerOrganisations_customPagination_returns200() {
        when(organisationService.listerOrganisationsActives(anyInt(), anyInt())).thenReturn(List.of());
        when(organisationService.compterOrganisationsActives()).thenReturn(50L);

        given()
                .queryParam("page", 2)
                .queryParam("size", 10)
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // listerOrganisations — GET / avec paramètre recherche
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations retourne 200 avec terme de recherche")
    void listerOrganisations_withRecherche_returns200() {
        when(organisationService.rechercherOrganisations(any(), anyInt(), anyInt())).thenReturn(List.of());
        when(organisationService.rechercherOrganisationsCount(any())).thenReturn(0L);

        given()
                .queryParam("recherche", "Association")
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // listerOrganisations — GET / avec rôle ADMIN_ORGANISATION
    // ============================================================

    @Test
    @TestSecurity(user = "orgadmin@test.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /api/organisations avec ADMIN_ORGANISATION retourne uniquement ses organisations")
    void listerOrganisations_adminOrganisation_returns200() {
        Organisation org = new Organisation();
        org.setId(UUID.randomUUID());
        org.setNom("Org Admin");
        org.setActif(true);

        when(organisationService.listerOrganisationsPourUtilisateur(any())).thenReturn(List.of(org));
        when(organisationService.convertToSummaryResponse(any(Organisation.class)))
                .thenReturn(new OrganisationSummaryResponse(org.getId(), "Org Admin", null, null, null, null, null, null, null, true, null, null));

        given()
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "orgadmin@test.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /api/organisations avec ADMIN_ORGANISATION et recherche filtre en mémoire")
    void listerOrganisations_adminOrganisationWithRecherche_returns200() {
        Organisation org = new Organisation();
        org.setId(UUID.randomUUID());
        org.setNom("Association Des Lions");
        org.setActif(true);

        when(organisationService.listerOrganisationsPourUtilisateur(any())).thenReturn(List.of(org));
        when(organisationService.convertToSummaryResponse(any(Organisation.class)))
                .thenReturn(new OrganisationSummaryResponse(org.getId(), "Association Des Lions", null, null, null, null, null, null, null, true, null, null));

        given()
                .queryParam("recherche", "Lions")
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // listerOrganisations — GET / accès public (@PermitAll)
    // ============================================================

    @Test
    @DisplayName("GET /api/organisations est accessible publiquement (sans auth)")
    void listerOrganisations_public_returns200() {
        when(organisationService.listerOrganisationsActives(anyInt(), anyInt())).thenReturn(List.of());
        when(organisationService.compterOrganisationsActives()).thenReturn(0L);

        given()
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // obtenirOrganisation — GET /{id}
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/{id} retourne 200 quand organisation trouvée")
    void obtenirOrganisation_found_returns200() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);
        org.setNom("Association Test");
        org.setActif(true);

        OrganisationResponse response = new OrganisationResponse();
        response.setId(id);
        response.setNom("Association Test");
        response.setStatut("ACTIVE");

        when(organisationService.trouverParId(id)).thenReturn(Optional.of(org));
        when(organisationService.convertToResponse(org)).thenReturn(response);

        given()
                .pathParam("id", id)
                .when()
                .get("/api/organisations/{id}")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/{id} retourne 404 quand organisation non trouvée")
    void obtenirOrganisation_notFound_returns404() {
        UUID id = UUID.randomUUID();
        when(organisationService.trouverParId(id)).thenReturn(Optional.empty());

        given()
                .pathParam("id", id)
                .when()
                .get("/api/organisations/{id}")
                .then()
                .statusCode(404);
    }

    // ============================================================
    // creerOrganisation — POST /
    // ============================================================

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/organisations retourne 201 avec données valides (SUPER_ADMIN)")
    void creerOrganisation_validRequest_returns201() {
        Organisation org = new Organisation();
        org.setId(UUID.randomUUID());
        org.setNom("Nouvelle Association");

        OrganisationResponse response = new OrganisationResponse();
        response.setId(org.getId());
        response.setNom("Nouvelle Association");
        response.setTypeOrganisation("ASSOCIATION");
        response.setStatut("ACTIVE");

        when(organisationService.convertFromCreateRequest(any(CreateOrganisationRequest.class))).thenReturn(org);
        when(organisationService.creerOrganisation(any(Organisation.class), anyString())).thenReturn(org);
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        Map<String, Object> body = Map.of(
                "nom", "Nouvelle Association",
                "typeOrganisation", "ASSOCIATION",
                "email", "nouvelle-asso@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(201)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/organisations retourne 409 quand organisation déjà existante (IAE)")
    void creerOrganisation_alreadyExists_IAE_returns409() {
        when(organisationService.convertFromCreateRequest(any(CreateOrganisationRequest.class)))
                .thenThrow(new IllegalArgumentException("Org déjà existante"));

        Map<String, Object> body = Map.of(
                "nom", "Association Existante",
                "typeOrganisation", "ASSOCIATION",
                "email", "existante@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(409);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/organisations retourne 409 quand IllegalStateException (ISE)")
    void creerOrganisation_alreadyExists_ISE_returns409() {
        when(organisationService.convertFromCreateRequest(any(CreateOrganisationRequest.class)))
                .thenThrow(new IllegalStateException("Email déjà utilisé par une autre organisation"));

        Map<String, Object> body = Map.of(
                "nom", "Autre Association",
                "typeOrganisation", "ASSOCIATION",
                "email", "existante@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(409);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/organisations retourne 500 sur erreur inattendue")
    void creerOrganisation_unexpectedError_returns500() {
        when(organisationService.convertFromCreateRequest(any(CreateOrganisationRequest.class)))
                .thenThrow(new RuntimeException("DB error"));

        Map<String, Object> body = Map.of(
                "nom", "Association Erreur",
                "typeOrganisation", "ASSOCIATION",
                "email", "erreur@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(500);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/organisations retourne 400 si champs obligatoires manquants")
    void creerOrganisation_missingFields_returns400() {
        Map<String, Object> body = Map.of(
                "typeOrganisation", "ASSOCIATION"
                // nom manquant (@NotBlank)
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(400);
    }

    // ============================================================
    // mettreAJourOrganisation — PUT /{id}
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("PUT /api/organisations/{id} retourne 200 avec mise à jour réussie")
    void mettreAJourOrganisation_success_returns200() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);
        org.setNom("Org Updated");

        OrganisationResponse response = new OrganisationResponse();
        response.setId(id);
        response.setNom("Org Updated");
        response.setTypeOrganisation("ASSOCIATION");

        when(organisationService.convertFromUpdateRequest(any(UpdateOrganisationRequest.class))).thenReturn(org);
        when(organisationService.mettreAJourOrganisation(eq(id), any(Organisation.class), anyString()))
                .thenReturn(org);
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        Map<String, Object> body = Map.of(
                "nom", "Org Updated",
                "typeOrganisation", "ASSOCIATION",
                "email", "updated@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .body(body)
                .when()
                .put("/api/organisations/{id}")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("PUT /api/organisations/{id} retourne 404 quand organisation non trouvée")
    void mettreAJourOrganisation_notFound_returns404() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);

        when(organisationService.convertFromUpdateRequest(any(UpdateOrganisationRequest.class))).thenReturn(org);
        when(organisationService.mettreAJourOrganisation(eq(id), any(Organisation.class), anyString()))
                .thenThrow(new NotFoundException("Organisation non trouvée avec l'ID: " + id));

        Map<String, Object> body = Map.of(
                "nom", "Org Inexistante",
                "typeOrganisation", "ASSOCIATION",
                "email", "inexistante@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .body(body)
                .when()
                .put("/api/organisations/{id}")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("PUT /api/organisations/{id} retourne 409 sur conflit (IAE)")
    void mettreAJourOrganisation_conflict_returns409() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);

        when(organisationService.convertFromUpdateRequest(any(UpdateOrganisationRequest.class))).thenReturn(org);
        when(organisationService.mettreAJourOrganisation(eq(id), any(Organisation.class), anyString()))
                .thenThrow(new IllegalArgumentException("Email déjà utilisé"));

        Map<String, Object> body = Map.of(
                "nom", "Org Conflit",
                "typeOrganisation", "ASSOCIATION",
                "email", "conflit@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .body(body)
                .when()
                .put("/api/organisations/{id}")
                .then()
                .statusCode(409);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("PUT /api/organisations/{id} retourne 500 sur erreur inattendue")
    void mettreAJourOrganisation_unexpectedError_returns500() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);

        when(organisationService.convertFromUpdateRequest(any(UpdateOrganisationRequest.class))).thenReturn(org);
        when(organisationService.mettreAJourOrganisation(eq(id), any(Organisation.class), anyString()))
                .thenThrow(new RuntimeException("DB error"));

        Map<String, Object> body = Map.of(
                "nom", "Org Erreur",
                "typeOrganisation", "ASSOCIATION",
                "email", "erreur@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .body(body)
                .when()
                .put("/api/organisations/{id}")
                .then()
                .statusCode(500);
    }

    // ============================================================
    // supprimerOrganisation — DELETE /{id}
    // ============================================================

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("DELETE /api/organisations/{id} retourne 204 après suppression (SUPER_ADMIN)")
    void supprimerOrganisation_success_returns204() {
        UUID id = UUID.randomUUID();
        doNothing().when(organisationService).supprimerOrganisation(eq(id), anyString());

        given()
                .pathParam("id", id)
                .when()
                .delete("/api/organisations/{id}")
                .then()
                .statusCode(204);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("DELETE /api/organisations/{id} retourne 404 quand organisation non trouvée (SUPER_ADMIN)")
    void supprimerOrganisation_notFound_returns404() {
        UUID id = UUID.randomUUID();
        doThrow(new NotFoundException("Organisation non trouvée"))
                .when(organisationService).supprimerOrganisation(eq(id), anyString());

        given()
                .pathParam("id", id)
                .when()
                .delete("/api/organisations/{id}")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("DELETE /api/organisations/{id} retourne 409 quand suppression impossible (ISE)")
    void supprimerOrganisation_hasMembers_returns409() {
        UUID id = UUID.randomUUID();
        doThrow(new IllegalStateException("L'organisation a des membres actifs"))
                .when(organisationService).supprimerOrganisation(eq(id), anyString());

        given()
                .pathParam("id", id)
                .when()
                .delete("/api/organisations/{id}")
                .then()
                .statusCode(409);
    }

    @Test
    @TestSecurity(user = "superadmin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("DELETE /api/organisations/{id} retourne 500 sur erreur inattendue")
    void supprimerOrganisation_unexpectedError_returns500() {
        UUID id = UUID.randomUUID();
        doThrow(new RuntimeException("DB error"))
                .when(organisationService).supprimerOrganisation(eq(id), anyString());

        given()
                .pathParam("id", id)
                .when()
                .delete("/api/organisations/{id}")
                .then()
                .statusCode(500);
    }

    // ============================================================
    // rechercheAvancee — GET /recherche
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/recherche retourne 200 avec critères")
    void rechercheAvancee_withCriteria_returns200() {
        Organisation org = new Organisation();
        org.setId(UUID.randomUUID());
        org.setNom("Lions Club Dakar");
        org.setActif(true);

        OrganisationResponse response = new OrganisationResponse();
        response.setId(org.getId());
        response.setNom("Lions Club Dakar");

        when(organisationService.rechercheAvancee(any(), any(), any(), any(), any(), any(), anyInt(), anyInt()))
                .thenReturn(List.of(org));
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        given()
                .queryParam("nom", "Lions")
                .queryParam("type", "ASSOCIATION")
                .queryParam("ville", "Dakar")
                .when()
                .get("/api/organisations/recherche")
                .then()
                .statusCode(200)
                .body("$", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/recherche retourne 200 avec liste vide")
    void rechercheAvancee_noResults_returns200() {
        when(organisationService.rechercheAvancee(any(), any(), any(), any(), any(), any(), anyInt(), anyInt()))
                .thenReturn(List.of());

        given()
                .queryParam("nom", "OrganisationInexistante")
                .when()
                .get("/api/organisations/recherche")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/recherche retourne 500 sur erreur de service")
    void rechercheAvancee_serviceError_returns500() {
        when(organisationService.rechercheAvancee(any(), any(), any(), any(), any(), any(), anyInt(), anyInt()))
                .thenThrow(new RuntimeException("Erreur DB"));

        given()
                .queryParam("nom", "Test")
                .when()
                .get("/api/organisations/recherche")
                .then()
                .statusCode(500);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/recherche retourne 200 sans paramètres")
    void rechercheAvancee_noParams_returns200() {
        when(organisationService.rechercheAvancee(any(), any(), any(), any(), any(), any(), anyInt(), anyInt()))
                .thenReturn(List.of());

        given()
                .when()
                .get("/api/organisations/recherche")
                .then()
                .statusCode(200);
    }

    // ============================================================
    // activerOrganisation — POST /{id}/activer
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/activer retourne 200 quand activation réussie")
    void activerOrganisation_success_returns200() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);
        org.setNom("Association Activée");
        org.setActif(true);

        OrganisationResponse response = new OrganisationResponse();
        response.setId(id);
        response.setStatut("ACTIVE");

        when(organisationService.activerOrganisation(eq(id), anyString())).thenReturn(org);
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/activer")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/activer retourne 404 quand organisation non trouvée")
    void activerOrganisation_notFound_returns404() {
        UUID id = UUID.randomUUID();
        when(organisationService.activerOrganisation(eq(id), anyString()))
                .thenThrow(new NotFoundException("Organisation non trouvée avec l'ID: " + id));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/activer")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/activer retourne 500 sur erreur inattendue")
    void activerOrganisation_unexpectedError_returns500() {
        UUID id = UUID.randomUUID();
        when(organisationService.activerOrganisation(eq(id), anyString()))
                .thenThrow(new RuntimeException("Erreur interne"));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/activer")
                .then()
                .statusCode(500);
    }

    // ============================================================
    // suspendreOrganisation — POST /{id}/suspendre
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/suspendre retourne 200 quand suspension réussie")
    void suspendreOrganisation_success_returns200() {
        UUID id = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(id);
        org.setNom("Association Suspendue");
        org.setActif(false);

        OrganisationResponse response = new OrganisationResponse();
        response.setId(id);
        response.setStatut("SUSPENDUE");

        when(organisationService.suspendreOrganisation(eq(id), anyString())).thenReturn(org);
        when(organisationService.convertToResponse(any(Organisation.class))).thenReturn(response);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/suspendre")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/suspendre retourne 404 quand organisation non trouvée")
    void suspendreOrganisation_notFound_returns404() {
        UUID id = UUID.randomUUID();
        when(organisationService.suspendreOrganisation(eq(id), anyString()))
                .thenThrow(new NotFoundException("Organisation non trouvée avec l'ID: " + id));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/suspendre")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/organisations/{id}/suspendre retourne 500 sur erreur inattendue")
    void suspendreOrganisation_unexpectedError_returns500() {
        UUID id = UUID.randomUUID();
        when(organisationService.suspendreOrganisation(eq(id), anyString()))
                .thenThrow(new RuntimeException("Erreur interne"));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", id)
                .when()
                .post("/api/organisations/{id}/suspendre")
                .then()
                .statusCode(500);
    }

    // ============================================================
    // obtenirStatistiques — GET /statistiques
    // ============================================================

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/statistiques retourne 200 avec statistiques")
    void obtenirStatistiques_returns200() {
        Map<String, Object> stats = Map.of(
                "totalOrganisations", 42L,
                "organisationsActives", 35L,
                "organisationsSuspendues", 7L,
                "nombreMembresTotal", 1200L
        );
        when(organisationService.obtenirStatistiques()).thenReturn(stats);

        given()
                .when()
                .get("/api/organisations/statistiques")
                .then()
                .statusCode(200)
                .body(notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/organisations/statistiques retourne 500 sur erreur de service")
    void obtenirStatistiques_serviceError_returns500() {
        when(organisationService.obtenirStatistiques())
                .thenThrow(new RuntimeException("Erreur base de données"));

        given()
                .when()
                .get("/api/organisations/statistiques")
                .then()
                .statusCode(500);
    }

    // ============================================================
    // Contrôle d'accès — vérification des rôles
    // ============================================================

    @Test
    @TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
    @DisplayName("GET /api/organisations retourne 200 pour MEMBRE (accès public)")
    void listerOrganisations_membre_returns200() {
        when(organisationService.listerOrganisationsActives(anyInt(), anyInt())).thenReturn(List.of());
        when(organisationService.compterOrganisationsActives()).thenReturn(0L);

        given()
                .when()
                .get("/api/organisations")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
    @DisplayName("POST /api/organisations retourne 403 pour MEMBRE (SUPER_ADMIN requis)")
    void creerOrganisation_membreRole_returns403() {
        Map<String, Object> body = Map.of(
                "nom", "Org par Membre",
                "typeOrganisation", "ASSOCIATION",
                "email", "membre-org@test.com"
        );

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/organisations")
                .then()
                .statusCode(403);
    }
}
