package dev.lions.unionflow.server.resource;

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

import dev.lions.unionflow.server.api.dto.organisation.OrganisationDTO;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.Test;

/**
 * Tests d'intégration pour OrganisationResource
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-15
 */
@QuarkusTest
class OrganisationResourceTest {

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testCreerOrganisation_Success() {
    OrganisationDTO organisation = createTestOrganisationDTO();

    given()
        .contentType(ContentType.JSON)
        .body(organisation)
        .when()
        .post("/api/organisations")
        .then()
        .statusCode(201)
        .body("nom", equalTo("Lions Club Test API"))
        .body("email", equalTo("testapi@lionsclub.org"))
        .body("actif", equalTo(true));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testCreerOrganisation_EmailInvalide() {
    OrganisationDTO organisation = createTestOrganisationDTO();
    organisation.setEmail("email-invalide");

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

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testCreerOrganisation_NomVide() {
    OrganisationDTO organisation = createTestOrganisationDTO();
    organisation.setNom("");

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

  @Test
  void testCreerOrganisation_NonAuthentifie() {
    OrganisationDTO organisation = createTestOrganisationDTO();

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

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testListerOrganisations_Success() {
    given()
        .when()
        .get("/api/organisations")
        .then()
        .statusCode(200)
        .body("size()", greaterThanOrEqualTo(0));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testListerOrganisations_AvecPagination() {
    given()
        .queryParam("page", 0)
        .queryParam("size", 10)
        .when()
        .get("/api/organisations")
        .then()
        .statusCode(200)
        .body("size()", greaterThanOrEqualTo(0));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testListerOrganisations_AvecRecherche() {
    given()
        .queryParam("recherche", "Lions")
        .when()
        .get("/api/organisations")
        .then()
        .statusCode(200)
        .body("size()", greaterThanOrEqualTo(0));
  }

  @Test
  void testListerOrganisations_NonAuthentifie() {
    given().when().get("/api/organisations").then().statusCode(401);
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testObtenirOrganisation_NonTrouvee() {
    given()
        .when()
        .get("/api/organisations/99999")
        .then()
        .statusCode(404)
        .body("error", equalTo("Organisation non trouvée"));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testMettreAJourOrganisation_NonTrouvee() {
    OrganisationDTO organisation = createTestOrganisationDTO();

    given()
        .contentType(ContentType.JSON)
        .body(organisation)
        .when()
        .put("/api/organisations/99999")
        .then()
        .statusCode(404)
        .body("error", containsString("Organisation non trouvée"));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testSupprimerOrganisation_NonTrouvee() {
    given()
        .when()
        .delete("/api/organisations/99999")
        .then()
        .statusCode(404)
        .body("error", containsString("Organisation non trouvée"));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testRechercheAvancee_Success() {
    given()
        .queryParam("nom", "Lions")
        .queryParam("ville", "Abidjan")
        .queryParam("page", 0)
        .queryParam("size", 10)
        .when()
        .get("/api/organisations/recherche")
        .then()
        .statusCode(200)
        .body("size()", greaterThanOrEqualTo(0));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testRechercheAvancee_SansCriteres() {
    given()
        .queryParam("page", 0)
        .queryParam("size", 10)
        .when()
        .get("/api/organisations/recherche")
        .then()
        .statusCode(200)
        .body("size()", greaterThanOrEqualTo(0));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testActiverOrganisation_NonTrouvee() {
    given()
        .when()
        .post("/api/organisations/99999/activer")
        .then()
        .statusCode(404)
        .body("error", containsString("Organisation non trouvée"));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testSuspendreOrganisation_NonTrouvee() {
    given()
        .when()
        .post("/api/organisations/99999/suspendre")
        .then()
        .statusCode(404)
        .body("error", containsString("Organisation non trouvée"));
  }

  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testObtenirStatistiques_Success() {
    given()
        .when()
        .get("/api/organisations/statistiques")
        .then()
        .statusCode(200)
        .body("totalOrganisations", notNullValue())
        .body("organisationsActives", notNullValue())
        .body("organisationsInactives", notNullValue())
        .body("nouvellesOrganisations30Jours", notNullValue())
        .body("tauxActivite", notNullValue())
        .body("timestamp", notNullValue());
  }

  @Test
  void testObtenirStatistiques_NonAuthentifie() {
    given().when().get("/api/organisations/statistiques").then().statusCode(401);
  }

  /** Test de workflow complet : création, lecture, mise à jour, suppression */
  @Test
  @TestSecurity(
      user = "testUser",
      roles = {"ADMIN"})
  void testWorkflowComplet() {
    // 1. Créer une organisation
    OrganisationDTO organisation = createTestOrganisationDTO();
    organisation.setNom("Lions Club Workflow Test");
    organisation.setEmail("workflow@lionsclub.org");

    String location =
        given()
            .contentType(ContentType.JSON)
            .body(organisation)
            .when()
            .post("/api/organisations")
            .then()
            .statusCode(201)
            .extract()
            .header("Location");

    // Extraire l'ID de l'organisation créée
    String organisationId = location.substring(location.lastIndexOf("/") + 1);

    // 2. Lire l'organisation créée
    given()
        .when()
        .get("/api/organisations/" + organisationId)
        .then()
        .statusCode(200)
        .body("nom", equalTo("Lions Club Workflow Test"))
        .body("email", equalTo("workflow@lionsclub.org"));

    // 3. Mettre à jour l'organisation
    organisation.setDescription("Description mise à jour");
    given()
        .contentType(ContentType.JSON)
        .body(organisation)
        .when()
        .put("/api/organisations/" + organisationId)
        .then()
        .statusCode(200)
        .body("description", equalTo("Description mise à jour"));

    // 4. Suspendre l'organisation
    given()
        .when()
        .post("/api/organisations/" + organisationId + "/suspendre")
        .then()
        .statusCode(200);

    // 5. Activer l'organisation
    given().when().post("/api/organisations/" + organisationId + "/activer").then().statusCode(200);

    // 6. Supprimer l'organisation (soft delete)
    given().when().delete("/api/organisations/" + organisationId).then().statusCode(204);
  }

  /** Crée un DTO d'organisation pour les tests */
  private OrganisationDTO createTestOrganisationDTO() {
    OrganisationDTO dto = new OrganisationDTO();
    dto.setId(UUID.randomUUID());
    dto.setNom("Lions Club Test API");
    dto.setNomCourt("LC Test API");
    dto.setEmail("testapi@lionsclub.org");
    dto.setDescription("Organisation de test pour l'API");
    dto.setTelephone("+225 01 02 03 04 05");
    dto.setAdresse("123 Rue de Test API");
    dto.setVille("Abidjan");
    dto.setCodePostal("00225");
    dto.setRegion("Lagunes");
    dto.setPays("Côte d'Ivoire");
    dto.setSiteWeb("https://testapi.lionsclub.org");
    dto.setObjectifs("Servir la communauté");
    dto.setActivitesPrincipales("Actions sociales et humanitaires");
    dto.setNombreMembres(0);
    dto.setDateCreation(LocalDateTime.now());
    dto.setActif(true);
    dto.setVersion(0L);

    return dto;
  }
}
