package dev.lions.unionflow.server.resource.registre;

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

import dev.lions.unionflow.server.api.enums.registre.StatutAgrement;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.registre.AgrementProfessionnel;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.registre.AgrementProfessionnelRepository;
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 java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class AgrementProfessionnelResourceTest {

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    MembreRepository membreRepository;

    @Inject
    AgrementProfessionnelRepository agrementProfessionnelRepository;

    private Organisation testOrganisation;
    private Membre testMembre;
    private AgrementProfessionnel testAgrement;

    @BeforeEach
    @Transactional
    void setupTestData() {
        testOrganisation = new Organisation();
        testOrganisation.setNom("Ordre Test " + UUID.randomUUID().toString().substring(0, 6));
        testOrganisation.setTypeOrganisation("ORDRE_PROFESSIONNEL");
        testOrganisation.setStatut("ACTIVE");
        testOrganisation.setEmail("ordre-res-" + UUID.randomUUID() + "@test.com");
        testOrganisation.setActif(true);
        testOrganisation.setDateCreation(LocalDateTime.now());
        organisationRepository.persist(testOrganisation);

        testMembre = Membre.builder()
                .numeroMembre("MBR-RES-" + UUID.randomUUID().toString().substring(0, 6))
                .prenom("Jean")
                .nom("Agrement")
                .email("agrement-res-" + UUID.randomUUID() + "@test.com")
                .dateNaissance(LocalDate.of(1985, 5, 15))
                .build();
        testMembre.setActif(true);
        testMembre.setDateCreation(LocalDateTime.now());
        membreRepository.persist(testMembre);

        testAgrement = AgrementProfessionnel.builder()
                .membre(testMembre)
                .organisation(testOrganisation)
                .statut(StatutAgrement.PROVISOIRE)
                .build();
        testAgrement.setActif(true);
        testAgrement.setDateCreation(LocalDateTime.now());
        agrementProfessionnelRepository.persist(testAgrement);
    }

    @AfterEach
    @Transactional
    void cleanupTestData() {
        if (testAgrement != null && testAgrement.getId() != null) {
            agrementProfessionnelRepository.deleteById(testAgrement.getId());
        }
        if (testMembre != null && testMembre.getId() != null) {
            membreRepository.deleteById(testMembre.getId());
        }
        if (testOrganisation != null && testOrganisation.getId() != null) {
            organisationRepository.deleteById(testOrganisation.getId());
        }
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "REGISTRE_RESP" })
    @DisplayName("GET /api/v1/registre/agrements/{id} inexistant retourne 404")
    void getAgrementById_inexistant_returns404() {
        given()
                .pathParam("id", UUID.randomUUID())
                .when()
                .get("/api/v1/registre/agrements/{id}")
                .then()
                .statusCode(404);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
    @DisplayName("GET /api/v1/registre/agrements/{id} existant retourne 200")
    void getAgrementById_existant_returns200() {
        given()
                .pathParam("id", testAgrement.getId())
                .when()
                .get("/api/v1/registre/agrements/{id}")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "REGISTRE_RESP" })
    @DisplayName("GET /api/v1/registre/agrements/membre/{id} retourne 200")
    void getAgrementsByMembre_returns200() {
        given()
                .pathParam("membreId", UUID.randomUUID())
                .when()
                .get("/api/v1/registre/agrements/membre/{membreId}")
                .then()
                .statusCode(200)
                .body("$", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "REGISTRE_RESP" })
    @DisplayName("GET /api/v1/registre/agrements/organisation/{id} retourne 200")
    void getAgrementsByOrganisation_returns200() {
        given()
                .pathParam("organisationId", UUID.randomUUID())
                .when()
                .get("/api/v1/registre/agrements/organisation/{organisationId}")
                .then()
                .statusCode(200)
                .body("$", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "REGISTRE_RESP" })
    @DisplayName("POST enregistrerAgrement avec membre et organisation valides retourne 201")
    void enregistrerAgrement_valid_returns201() {
        String body = "{"
                + "\"membreId\": \"" + testMembre.getId() + "\","
                + "\"organisationId\": \"" + testOrganisation.getId() + "\","
                + "\"statut\": \"PROVISOIRE\""
                + "}";
        String agrementId = given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/v1/registre/agrements")
                .then()
                .statusCode(201)
                .body("id", notNullValue())
                .extract().path("id");

        if (agrementId != null) {
            try {
                cleanupAgrement(UUID.fromString(agrementId));
            } catch (Exception e) {
                // best effort
            }
        }
    }

    @Transactional
    void cleanupAgrement(UUID id) {
        agrementProfessionnelRepository.deleteById(id);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "REGISTRE_RESP" })
    @DisplayName("POST /api/v1/registre/agrements avec corps vide retourne 4xx")
    void enregistrerAgrement_corpsVide_returns4xx() {
        given()
                .contentType(ContentType.JSON)
                .body("{}")
                .when()
                .post("/api/v1/registre/agrements")
                .then()
                .statusCode(anyOf(equalTo(400), equalTo(500)));
    }
}
