package dev.lions.unionflow.server.integration;

import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.*;

import java.util.UUID;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.*;

/**
 * Tests d'intégration End-to-End pour le workflow complet d'une organisation
 * 
 * Scénario testé :
 * 1. Création d'une nouvelle organisation
 * 2. Consultation des détails
 * 3. Modification des informations
 * 4. Suspension
 * 5. Réactivation
 * 
 * @author UnionFlow Team
 * @version 3.0
 * @since 2026-01-04
 */
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class OrganisationWorkflowIntegrationTest {

    private static final String BASE_PATH = "/api/organisations";

    @Inject
    OrganisationRepository organisationRepository;

    private UUID organisationId;
    private String organisationEmail;

    @Test
    @Order(1)
    @TestSecurity(user = "superadmin@unionflow.com", roles = { "SUPER_ADMIN" })
    @DisplayName("E2E-01: Créer une nouvelle organisation")
    void test01_CreerOrganisation() {
        organisationEmail = "org-e2e-" + System.currentTimeMillis() + "@test.com";

        String orgJson = String.format("""
                {
                  "nom": "Organisation E2E Test",
                  "typeOrganisation": "ASSOCIATION",
                  "statut": "ACTIVE",
                  "email": "%s",
                  "telephone": "+221701234567",
                  "adresse": "123 Rue Test, Dakar",
                  "ville": "Dakar",
                  "pays": "Sénégal"
                }
                """, organisationEmail);

        String idStr = given()
                .contentType(ContentType.JSON)
                .body(orgJson)
                .when()
                .post(BASE_PATH)
                .then()
                .statusCode(201)
                .contentType(ContentType.JSON)
                .body("nom", equalTo("Organisation E2E Test"))
                .body("statut", equalTo("ACTIVE"))
                .body("id", notNullValue())
                .extract()
                .path("id");

        organisationId = UUID.fromString(idStr);
        assertNotNull(organisationId, "L'ID de l'organisation doit être retourné");
    }

    @Test
    @Order(2)
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("E2E-02: Consulter les détails de l'organisation")
    void test02_ConsulterOrganisation() {
        given()
                .pathParam("id", organisationId)
                .when()
                .get(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("id", equalTo(organisationId.toString()))
                .body("nom", equalTo("Organisation E2E Test"))
                .body("email", equalTo(organisationEmail));
    }

    @Test
    @Order(3)
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("E2E-03: Modifier l'organisation")
    void test03_ModifierOrganisation() {
        String updateJson = String.format("""
                {
                  "nom": "Organisation E2E Test Modifiée",
                  "typeOrganisation": "ASSOCIATION",
                  "statut": "ACTIVE",
                  "email": "%s",
                  "telephone": "+221709876543",
                  "adresse": "456 Avenue Nouvelle, Dakar"
                }
                """, organisationEmail);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", organisationId)
                .body(updateJson)
                .when()
                .put(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .body("nom", equalTo("Organisation E2E Test Modifiée"))
                .body("telephone", equalTo("+221709876543"));
    }

    @Test
    @Order(4)
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("E2E-04: Changer le statut à SUSPENDU")
    void test04_SuspendreOrganisation() {
        String updateJson = String.format("""
                {
                  "nom": "Organisation E2E Test Modifiée",
                  "typeOrganisation": "ASSOCIATION",
                  "statut": "SUSPENDUE",
                  "email": "%s",
                  "telephone": "+221709876543"
                }
                """, organisationEmail);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", organisationId)
                .body(updateJson)
                .when()
                .put(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .body("statut", equalTo("SUSPENDUE"));
    }

    @Test
    @Order(5)
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("E2E-05: Réactiver en changeant le statut")
    void test05_ReactiverOrganisation() {
        String updateJson = String.format("""
                {
                  "nom": "Organisation E2E Test Modifiée",
                  "typeOrganisation": "ASSOCIATION",
                  "statut": "ACTIVE",
                  "email": "%s",
                  "telephone": "+221709876543"
                }
                """, organisationEmail);

        given()
                .contentType(ContentType.JSON)
                .pathParam("id", organisationId)
                .body(updateJson)
                .when()
                .put(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .body("statut", equalTo("ACTIVE"));
    }

    @Test
    @Order(6)
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("E2E-06: Lister toutes les organisations (pagination)")
    void test06_ListerOrganisations() {
        given()
                .queryParam("page", 0)
                .queryParam("size", 10)
                .when()
                .get(BASE_PATH)
                .then()
                .statusCode(200)
                .body("data", notNullValue())
                .body("data", hasSize(greaterThan(0)))
                .body("total", greaterThan(0));
    }

    @AfterAll
    @Transactional
    void cleanup() {
        if (organisationId != null) {
            organisationRepository.findByIdOptional(organisationId)
                    .ifPresent(org -> organisationRepository.delete(org));
        }
    }
}
