package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
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.ArgumentMatchers.isNull;
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.souscription.FormuleAbonnementResponse;
import dev.lions.unionflow.server.api.dto.souscription.SouscriptionDemandeRequest;
import dev.lions.unionflow.server.api.dto.souscription.SouscriptionStatutResponse;
import dev.lions.unionflow.server.service.SouscriptionService;
import dev.lions.unionflow.server.service.support.SecuriteHelper;
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.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
 * Tests mock pour SouscriptionResource — couvre tous les endpoints.
 *
 * <p>Catégories testées :
 * <ul>
 *   <li>Endpoints publics (PermitAll) : GET /formules, POST /confirmer-paiement</li>
 *   <li>Endpoints @Authenticated : GET /ma-souscription, POST /demande, POST /{id}/initier-paiement</li>
 *   <li>Endpoints SUPER_ADMIN : GET /admin/toutes, GET /admin/organisation/{id}/active,
 *       GET /admin/en-attente, POST /admin/{id}/approuver, POST /admin/{id}/rejeter</li>
 * </ul>
 */
@QuarkusTest
@DisplayName("SouscriptionResource (mock)")
class SouscriptionResourceMockTest {

    @InjectMock
    SouscriptionService souscriptionService;

    @InjectMock
    SecuriteHelper securiteHelper;

    // ── Helper ────────────────────────────────────────────────────────────────

    private SouscriptionStatutResponse buildStatut(String statutValidation) {
        SouscriptionStatutResponse r = new SouscriptionStatutResponse();
        r.setSouscriptionId(UUID.randomUUID().toString());
        r.setStatutValidation(statutValidation);
        r.setStatutLibelle(statutValidation);
        r.setMontantTotal(new BigDecimal("10000"));
        r.setOrganisationId(UUID.randomUUID().toString());
        r.setOrganisationNom("Org Test");
        return r;
    }

    private FormuleAbonnementResponse buildFormule() {
        FormuleAbonnementResponse f = new FormuleAbonnementResponse();
        f.setCode("BASIC");
        f.setLibelle("Formule Basic");
        f.setDescription("Formule de base");
        f.setPlage("PETITE");
        f.setPrixMensuel(new BigDecimal("3000"));
        return f;
    }

    // ── GET /api/souscriptions/formules — PUBLIC ──────────────────────────────

    @Test
    @DisplayName("GET /formules — retourne 200 avec la liste des formules (PermitAll)")
    void getFormules_success_returns200() {
        when(souscriptionService.getFormules()).thenReturn(List.of(buildFormule()));

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

    @Test
    @DisplayName("GET /formules — retourne 200 même avec liste vide (PermitAll)")
    void getFormules_listeVide_returns200() {
        when(souscriptionService.getFormules()).thenReturn(List.of());

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

    // ── POST /api/souscriptions/confirmer-paiement — PUBLIC ──────────────────

    @Test
    @DisplayName("POST /confirmer-paiement — retourne 200 quand paiement confirmé avec succès")
    void confirmerPaiement_success_returns200() {
        UUID souscriptionId = UUID.randomUUID();
        doNothing().when(souscriptionService).confirmerPaiement(eq(souscriptionId), anyString());

        given()
                .queryParam("id", souscriptionId.toString())
                .queryParam("wave_id", "WAVE-TXN-12345")
                .when()
                .post("/api/souscriptions/confirmer-paiement")
                .then()
                .statusCode(200)
                .body("message", equalTo("Paiement confirmé — compte activé"));
    }

    @Test
    @DisplayName("POST /confirmer-paiement — retourne 200 sans wave_id (optionnel)")
    void confirmerPaiement_sansWaveId_returns200() {
        UUID souscriptionId = UUID.randomUUID();
        doNothing().when(souscriptionService).confirmerPaiement(eq(souscriptionId), isNull());

        given()
                .queryParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/confirmer-paiement")
                .then()
                .statusCode(200);
    }

    @Test
    @DisplayName("POST /confirmer-paiement — retourne 400 si paramètre id manquant")
    void confirmerPaiement_idManquant_returns400() {
        given()
                .queryParam("wave_id", "WAVE-TXN-99")
                .when()
                .post("/api/souscriptions/confirmer-paiement")
                .then()
                .statusCode(400);
    }

    @Test
    @DisplayName("POST /confirmer-paiement — retourne 400 si service lève BadRequestException (statut invalide)")
    void confirmerPaiement_statutInvalide_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        doThrow(new BadRequestException("Impossible de confirmer depuis le statut: REJETEE"))
                .when(souscriptionService).confirmerPaiement(eq(souscriptionId), anyString());

        given()
                .queryParam("id", souscriptionId.toString())
                .queryParam("wave_id", "WAVE-TXN-BAD")
                .when()
                .post("/api/souscriptions/confirmer-paiement")
                .then()
                .statusCode(400);
    }

    @Test
    @DisplayName("POST /confirmer-paiement — retourne 404 si souscription introuvable")
    void confirmerPaiement_souscriptionInconnue_returns404() {
        UUID souscriptionId = UUID.randomUUID();
        doThrow(new NotFoundException("Souscription introuvable: " + souscriptionId))
                .when(souscriptionService).confirmerPaiement(eq(souscriptionId), anyString());

        given()
                .queryParam("id", souscriptionId.toString())
                .queryParam("wave_id", "WAVE-TXN-INCO")
                .when()
                .post("/api/souscriptions/confirmer-paiement")
                .then()
                .statusCode(404);
    }

    // ── GET /api/souscriptions/ma-souscription — @Authenticated ──────────────

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /ma-souscription — retourne 200 quand souscription trouvée")
    void getMaSouscription_success_returns200() {
        SouscriptionStatutResponse statut = buildStatut("ACTIVE");
        when(souscriptionService.getMaSouscription()).thenReturn(statut);

        given()
                .when()
                .get("/api/souscriptions/ma-souscription")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /ma-souscription — retourne 404 si aucune souscription pour ce membre")
    void getMaSouscription_aucuneSouscription_returns404() {
        when(souscriptionService.getMaSouscription())
                .thenThrow(new NotFoundException("Aucune souscription trouvée pour ce membre"));

        given()
                .when()
                .get("/api/souscriptions/ma-souscription")
                .then()
                .statusCode(404);
    }

    @Test
    @DisplayName("GET /ma-souscription — retourne 401 sans authentification")
    void getMaSouscription_nonAuthentifie_returns401() {
        given()
                .when()
                .get("/api/souscriptions/ma-souscription")
                .then()
                .statusCode(401);
    }

    // ── POST /api/souscriptions/demande — @Authenticated ─────────────────────

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /demande — retourne 201 quand demande créée avec succès")
    void creerDemande_success_returns201() {
        SouscriptionStatutResponse statut = buildStatut("EN_ATTENTE_PAIEMENT");
        when(souscriptionService.creerDemande(any(SouscriptionDemandeRequest.class))).thenReturn(statut);

        String body = """
                {
                  "typeFormule": "BASIC",
                  "plageMembres": "PETITE",
                  "typePeriode": "MENSUEL",
                  "typeOrganisation": "ASSOCIATION",
                  "organisationId": "%s"
                }
                """.formatted(UUID.randomUUID());

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/souscriptions/demande")
                .then()
                .statusCode(201);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /demande — retourne 400 si organisation introuvable")
    void creerDemande_orgInconnue_returns400() {
        when(souscriptionService.creerDemande(any(SouscriptionDemandeRequest.class)))
                .thenThrow(new NotFoundException("Organisation introuvable"));

        String body = """
                {
                  "typeFormule": "BASIC",
                  "plageMembres": "PETITE",
                  "typePeriode": "MENSUEL",
                  "organisationId": "%s"
                }
                """.formatted(UUID.randomUUID());

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/souscriptions/demande")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /demande — retourne 400 si souscription déjà existante pour l'organisation")
    void creerDemande_souscriptionExistante_returns400() {
        when(souscriptionService.creerDemande(any(SouscriptionDemandeRequest.class)))
                .thenThrow(new BadRequestException("Une souscription en cours existe déjà pour cette organisation"));

        String body = """
                {
                  "typeFormule": "BASIC",
                  "plageMembres": "PETITE",
                  "typePeriode": "MENSUEL",
                  "organisationId": "%s"
                }
                """.formatted(UUID.randomUUID());

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

    @Test
    @DisplayName("POST /demande — retourne 401 sans authentification")
    void creerDemande_nonAuthentifie_returns401() {
        given()
                .contentType(ContentType.JSON)
                .body("{}")
                .when()
                .post("/api/souscriptions/demande")
                .then()
                .statusCode(401);
    }

    // ── POST /api/souscriptions/{id}/initier-paiement — @Authenticated ───────

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /{id}/initier-paiement — retourne 200 avec waveLaunchUrl quand session créée")
    void initierPaiement_success_returns200() {
        UUID souscriptionId = UUID.randomUUID();
        SouscriptionStatutResponse statut = buildStatut("PAIEMENT_INITIE");
        statut.setWaveLaunchUrl("https://pay.wave.com/checkout/abc123");
        when(souscriptionService.initierPaiementWave(souscriptionId)).thenReturn(statut);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/{id}/initier-paiement")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /{id}/initier-paiement — retourne 404 si souscription introuvable")
    void initierPaiement_souscriptionInconnue_returns404() {
        UUID souscriptionId = UUID.randomUUID();
        when(souscriptionService.initierPaiementWave(souscriptionId))
                .thenThrow(new NotFoundException("Souscription introuvable: " + souscriptionId));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/{id}/initier-paiement")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /{id}/initier-paiement — retourne 400 si statut invalide pour paiement")
    void initierPaiement_statutInvalide_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        when(souscriptionService.initierPaiementWave(souscriptionId))
                .thenThrow(new BadRequestException("Impossible d'initier le paiement depuis le statut: VALIDEE"));

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/{id}/initier-paiement")
                .then()
                .statusCode(400);
    }

    @Test
    @DisplayName("POST /{id}/initier-paiement — retourne 401 sans authentification")
    void initierPaiement_nonAuthentifie_returns401() {
        given()
                .contentType(ContentType.JSON)
                .pathParam("id", UUID.randomUUID().toString())
                .when()
                .post("/api/souscriptions/{id}/initier-paiement")
                .then()
                .statusCode(401);
    }

    // ── GET /api/souscriptions/admin/toutes — SUPER_ADMIN ────────────────────

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/toutes — retourne 200 avec liste complète")
    void getSouscriptionsToutes_success_returns200() {
        when(souscriptionService.listerToutes(isNull(), eq(0), eq(1000)))
                .thenReturn(List.of(buildStatut("ACTIVE"), buildStatut("EN_ATTENTE_PAIEMENT")));

        given()
                .when()
                .get("/api/souscriptions/admin/toutes")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/toutes — retourne 200 avec filtre organisationId")
    void getSouscriptionsToutes_avecFiltreOrg_returns200() {
        UUID orgId = UUID.randomUUID();
        when(souscriptionService.listerToutes(eq(orgId), anyInt(), anyInt()))
                .thenReturn(List.of(buildStatut("ACTIVE")));

        given()
                .queryParam("organisationId", orgId.toString())
                .when()
                .get("/api/souscriptions/admin/toutes")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/toutes — retourne 200 avec liste vide")
    void getSouscriptionsToutes_listeVide_returns200() {
        when(souscriptionService.listerToutes(isNull(), anyInt(), anyInt()))
                .thenReturn(List.of());

        given()
                .when()
                .get("/api/souscriptions/admin/toutes")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /admin/toutes — retourne 403 si rôle insuffisant (ADMIN_ORGANISATION)")
    void getSouscriptionsToutes_roleInsuffisant_returns403() {
        given()
                .when()
                .get("/api/souscriptions/admin/toutes")
                .then()
                .statusCode(403);
    }

    // ── GET /api/souscriptions/admin/organisation/{id}/active — SUPER_ADMIN ──

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/organisation/{orgId}/active — retourne 200 quand souscription active trouvée")
    void getActiveParOrganisation_success_returns200() {
        UUID orgId = UUID.randomUUID();
        when(souscriptionService.obtenirActiveParOrganisation(orgId))
                .thenReturn(buildStatut("ACTIVE"));

        given()
                .pathParam("organisationId", orgId.toString())
                .when()
                .get("/api/souscriptions/admin/organisation/{organisationId}/active")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/organisation/{orgId}/active — retourne 404 si aucune souscription active")
    void getActiveParOrganisation_aucuneActive_returns404() {
        UUID orgId = UUID.randomUUID();
        when(souscriptionService.obtenirActiveParOrganisation(orgId)).thenReturn(null);

        given()
                .pathParam("organisationId", orgId.toString())
                .when()
                .get("/api/souscriptions/admin/organisation/{organisationId}/active")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /admin/organisation/{orgId}/active — retourne 403 si rôle insuffisant")
    void getActiveParOrganisation_roleInsuffisant_returns403() {
        given()
                .pathParam("organisationId", UUID.randomUUID().toString())
                .when()
                .get("/api/souscriptions/admin/organisation/{organisationId}/active")
                .then()
                .statusCode(403);
    }

    // ── GET /api/souscriptions/admin/en-attente — SUPER_ADMIN ────────────────

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/en-attente — retourne 200 avec liste des souscriptions en attente")
    void getSouscriptionsEnAttente_success_returns200() {
        when(souscriptionService.getSouscriptionsEnAttenteValidation())
                .thenReturn(List.of(buildStatut("PAIEMENT_CONFIRME")));

        given()
                .when()
                .get("/api/souscriptions/admin/en-attente")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("GET /admin/en-attente — retourne 200 avec liste vide si aucune en attente")
    void getSouscriptionsEnAttente_listeVide_returns200() {
        when(souscriptionService.getSouscriptionsEnAttenteValidation()).thenReturn(List.of());

        given()
                .when()
                .get("/api/souscriptions/admin/en-attente")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("GET /admin/en-attente — retourne 403 si rôle insuffisant (ADMIN_ORGANISATION)")
    void getSouscriptionsEnAttente_roleInsuffisant_returns403() {
        given()
                .when()
                .get("/api/souscriptions/admin/en-attente")
                .then()
                .statusCode(403);
    }

    @Test
    @DisplayName("GET /admin/en-attente — retourne 401 sans authentification")
    void getSouscriptionsEnAttente_nonAuthentifie_returns401() {
        given()
                .when()
                .get("/api/souscriptions/admin/en-attente")
                .then()
                .statusCode(401);
    }

    // ── POST /api/souscriptions/admin/{id}/approuver — SUPER_ADMIN ───────────

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/approuver — retourne 200 quand approbation réussie")
    void approuver_success_returns200() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doNothing().when(souscriptionService).approuver(souscriptionId, superAdminId);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/admin/{id}/approuver")
                .then()
                .statusCode(200)
                .body("message", equalTo("Souscription approuvée — compte activé"));
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/approuver — retourne 404 si souscription introuvable")
    void approuver_souscriptionInconnue_returns404() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doThrow(new NotFoundException("Souscription introuvable: " + souscriptionId))
                .when(souscriptionService).approuver(souscriptionId, superAdminId);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/admin/{id}/approuver")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/approuver — retourne 400 si statut non approuvable")
    void approuver_statutNonApprouvable_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doThrow(new BadRequestException("Impossible d'approuver depuis le statut: EN_ATTENTE_PAIEMENT"))
                .when(souscriptionService).approuver(souscriptionId, superAdminId);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .when()
                .post("/api/souscriptions/admin/{id}/approuver")
                .then()
                .statusCode(400);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /admin/{id}/approuver — retourne 403 si rôle insuffisant")
    void approuver_roleInsuffisant_returns403() {
        given()
                .contentType(ContentType.JSON)
                .pathParam("id", UUID.randomUUID().toString())
                .when()
                .post("/api/souscriptions/admin/{id}/approuver")
                .then()
                .statusCode(403);
    }

    // ── POST /api/souscriptions/admin/{id}/rejeter — SUPER_ADMIN ─────────────

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 200 quand rejet réussi avec commentaire")
    void rejeter_success_returns200() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doNothing().when(souscriptionService).rejeter(eq(souscriptionId), eq(superAdminId), anyString());

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .body(Map.of("commentaire", "Documents manquants — dossier incomplet"))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(200)
                .body("message", equalTo("Souscription rejetée"));
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 400 si commentaire absent")
    void rejeter_sansCommentaire_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(UUID.randomUUID());

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .body(Map.of())
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(400);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 400 si commentaire vide (blank)")
    void rejeter_commentaireVide_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(UUID.randomUUID());

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .body(Map.of("commentaire", "   "))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(400);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 404 si souscription introuvable")
    void rejeter_souscriptionInconnue_returns404() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doThrow(new NotFoundException("Souscription introuvable: " + souscriptionId))
                .when(souscriptionService).rejeter(eq(souscriptionId), eq(superAdminId), anyString());

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .body(Map.of("commentaire", "Motif de rejet"))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 400 si souscription déjà dans état terminal")
    void rejeter_etatTerminal_returns400() {
        UUID souscriptionId = UUID.randomUUID();
        UUID superAdminId = UUID.randomUUID();
        when(securiteHelper.resolveMembreId()).thenReturn(superAdminId);
        doThrow(new BadRequestException("La souscription est déjà dans un état terminal: REJETEE"))
                .when(souscriptionService).rejeter(eq(souscriptionId), eq(superAdminId), anyString());

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", souscriptionId.toString())
                .body(Map.of("commentaire", "Motif de rejet"))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(400);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN_ORGANISATION"})
    @DisplayName("POST /admin/{id}/rejeter — retourne 403 si rôle insuffisant")
    void rejeter_roleInsuffisant_returns403() {
        given()
                .contentType(ContentType.JSON)
                .pathParam("id", UUID.randomUUID().toString())
                .body(Map.of("commentaire", "Rejet non autorisé"))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(403);
    }

    @Test
    @DisplayName("POST /admin/{id}/rejeter — retourne 401 sans authentification")
    void rejeter_nonAuthentifie_returns401() {
        given()
                .contentType(ContentType.JSON)
                .pathParam("id", UUID.randomUUID().toString())
                .body(Map.of("commentaire", "test"))
                .when()
                .post("/api/souscriptions/admin/{id}/rejeter")
                .then()
                .statusCode(401);
    }
}
