package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/** Tests d'intégration complets pour MembreResource Couvre tous les endpoints et cas d'erreur */
@QuarkusTest
@DisplayName("Tests d'intégration complets MembreResource")
class MembreResourceCompleteIntegrationTest {

  @Test
  @DisplayName("POST /api/membres - Création avec email existant")
  void testCreerMembreEmailExistant() {
    // Créer un premier membre
    String membreJson1 =
        """
        {
            "numeroMembre": "UF2025-EXIST01",
            "prenom": "Premier",
            "nom": "Membre",
            "email": "existe@test.com",
            "telephone": "221701234567",
            "dateNaissance": "1990-05-15",
            "dateAdhesion": "2025-01-10",
            "actif": true
        }
        """;

    given()
        .contentType(ContentType.JSON)
        .body(membreJson1)
        .when()
        .post("/api/membres")
        .then()
        .statusCode(anyOf(is(201), is(400))); // 201 si nouveau, 400 si existe déjà

    // Essayer de créer un deuxième membre avec le même email
    String membreJson2 =
        """
        {
            "numeroMembre": "UF2025-EXIST02",
            "prenom": "Deuxieme",
            "nom": "Membre",
            "email": "existe@test.com",
            "telephone": "221701234568",
            "dateNaissance": "1985-08-20",
            "dateAdhesion": "2025-01-10",
            "actif": true
        }
        """;

    given()
        .contentType(ContentType.JSON)
        .body(membreJson2)
        .when()
        .post("/api/membres")
        .then()
        .statusCode(400)
        .body("message", notNullValue());
  }

  @Test
  @DisplayName("POST /api/membres - Validation des champs obligatoires")
  void testCreerMembreValidationChamps() {
    // Test avec prénom manquant
    String membreSansPrenom =
        """
        {
            "nom": "Test",
            "email": "test.sans.prenom@test.com",
            "telephone": "221701234567"
        }
        """;

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

    // Test avec email invalide
    String membreEmailInvalide =
        """
        {
            "prenom": "Test",
            "nom": "Test",
            "email": "email-invalide",
            "telephone": "221701234567"
        }
        """;

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

  @Test
  @DisplayName("PUT /api/membres/{id} - Mise à jour membre existant")
  void testMettreAJourMembreExistant() {
    // D'abord créer un membre
    String membreOriginal =
        """
        {
            "numeroMembre": "UF2025-UPDATE01",
            "prenom": "Original",
            "nom": "Membre",
            "email": "original.update@test.com",
            "telephone": "221701234567",
            "dateNaissance": "1990-05-15",
            "dateAdhesion": "2025-01-10",
            "actif": true
        }
        """;

    // Créer le membre (peut réussir ou échouer si existe déjà)
    given()
        .contentType(ContentType.JSON)
        .body(membreOriginal)
        .when()
        .post("/api/membres")
        .then()
        .statusCode(anyOf(is(201), is(400)));

    // Essayer de mettre à jour avec ID 1 (peut exister ou non)
    String membreMisAJour =
        """
        {
            "numeroMembre": "UF2025-UPDATE01",
            "prenom": "Modifie",
            "nom": "Membre",
            "email": "modifie.update@test.com",
            "telephone": "221701234567",
            "dateNaissance": "1990-05-15",
            "dateAdhesion": "2025-01-10",
            "actif": true
        }
        """;

    given()
        .contentType(ContentType.JSON)
        .body(membreMisAJour)
        .when()
        .put("/api/membres/1")
        .then()
        .statusCode(anyOf(is(200), is(400))); // 200 si trouvé, 400 si non trouvé
  }

  @Test
  @DisplayName("PUT /api/membres/{id} - Membre inexistant")
  void testMettreAJourMembreInexistant() {
    String membreJson =
        """
        {
            "numeroMembre": "UF2025-INEXIST01",
            "prenom": "Inexistant",
            "nom": "Membre",
            "email": "inexistant@test.com",
            "telephone": "221701234567",
            "dateNaissance": "1990-05-15",
            "dateAdhesion": "2025-01-10",
            "actif": true
        }
        """;

    given()
        .contentType(ContentType.JSON)
        .body(membreJson)
        .when()
        .put("/api/membres/99999")
        .then()
        .statusCode(400)
        .body("message", notNullValue());
  }

  @Test
  @DisplayName("DELETE /api/membres/{id} - Désactiver membre existant")
  void testDesactiverMembreExistant() {
    // Essayer de désactiver le membre ID 1 (peut exister ou non)
    given()
        .when()
        .delete("/api/membres/1")
        .then()
        .statusCode(anyOf(is(204), is(404))); // 204 si trouvé, 404 si non trouvé
  }

  @Test
  @DisplayName("DELETE /api/membres/{id} - Membre inexistant")
  void testDesactiverMembreInexistant() {
    given()
        .when()
        .delete("/api/membres/99999")
        .then()
        .statusCode(404)
        .body("message", notNullValue());
  }

  @Test
  @DisplayName("GET /api/membres/{id} - Membre existant")
  void testObtenirMembreExistant() {
    // Essayer d'obtenir le membre ID 1 (peut exister ou non)
    given()
        .when()
        .get("/api/membres/1")
        .then()
        .statusCode(anyOf(is(200), is(404))); // 200 si trouvé, 404 si non trouvé
  }

  @Test
  @DisplayName("GET /api/membres/{id} - Membre inexistant")
  void testObtenirMembreInexistant() {
    given()
        .when()
        .get("/api/membres/99999")
        .then()
        .statusCode(404)
        .body("message", equalTo("Membre non trouvé"));
  }

  @Test
  @DisplayName("GET /api/membres/recherche - Recherche avec terme null")
  void testRechercherMembresTermeNull() {
    given()
        .when()
        .get("/api/membres/recherche")
        .then()
        .statusCode(400)
        .body("message", equalTo("Le terme de recherche est requis"));
  }

  @Test
  @DisplayName("GET /api/membres/recherche - Recherche avec terme valide")
  void testRechercherMembresTermeValide() {
    given()
        .queryParam("q", "test")
        .when()
        .get("/api/membres/recherche")
        .then()
        .statusCode(200)
        .contentType(ContentType.JSON);
  }

  @Test
  @DisplayName("Test des headers HTTP")
  void testHeadersHTTP() {
    // Test avec différents Accept headers
    given()
        .accept(ContentType.JSON)
        .when()
        .get("/api/membres")
        .then()
        .statusCode(200)
        .contentType(ContentType.JSON);

    given()
        .accept(ContentType.XML)
        .when()
        .get("/api/membres")
        .then()
        .statusCode(anyOf(is(200), is(406))); // 200 si supporté, 406 si non supporté
  }

  @Test
  @DisplayName("Test des méthodes HTTP non supportées")
  void testMethodesHTTPNonSupportees() {
    // OPTIONS peut être supporté ou non
    given().when().options("/api/membres").then().statusCode(anyOf(is(200), is(405)));

    // HEAD peut être supporté ou non
    given().when().head("/api/membres").then().statusCode(anyOf(is(200), is(405)));
  }

  @Test
  @DisplayName("Test de performance et robustesse")
  void testPerformanceEtRobustesse() {
    // Test avec une grande quantité de données
    StringBuilder largeJson = new StringBuilder();
    largeJson.append("{");
    largeJson.append("\"prenom\": \"").append("A".repeat(100)).append("\",");
    largeJson.append("\"nom\": \"").append("B".repeat(100)).append("\",");
    largeJson.append("\"email\": \"large.test@test.com\",");
    largeJson.append("\"telephone\": \"221701234567\"");
    largeJson.append("}");

    given()
        .contentType(ContentType.JSON)
        .body(largeJson.toString())
        .when()
        .post("/api/membres")
        .then()
        .statusCode(anyOf(is(201), is(400))); // Peut réussir ou échouer selon la validation
  }

  @Test
  @DisplayName("Test de gestion des erreurs serveur")
  void testGestionErreursServeur() {
    // Test avec des données qui peuvent causer des erreurs internes
    String jsonMalformed = "{ invalid json }";

    given()
        .contentType(ContentType.JSON)
        .body(jsonMalformed)
        .when()
        .post("/api/membres")
        .then()
        .statusCode(400); // Bad Request pour JSON malformé
  }
}
