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

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

import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.collectefonds.CampagneCollecte;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.collectefonds.CampagneCollecteRepository;
import dev.lions.unionflow.server.repository.collectefonds.ContributionCollecteRepository;
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.math.BigDecimal;
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 CampagneCollecteResourceTest {

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    CampagneCollecteRepository campagneCollecteRepository;

    @Inject
    ContributionCollecteRepository contributionCollecteRepository;

    private Organisation testOrganisation;
    private CampagneCollecte testCampagne;
    private CampagneCollecte testCampagneEnCours;

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

        testCampagne = CampagneCollecte.builder()
                .organisation(testOrganisation)
                .titre("Campagne Collecte Test Resource")
                .statut(StatutCampagneCollecte.BROUILLON)
                .build();
        testCampagne.setActif(true);
        testCampagne.setDateCreation(LocalDateTime.now());
        campagneCollecteRepository.persist(testCampagne);

        testCampagneEnCours = CampagneCollecte.builder()
                .organisation(testOrganisation)
                .titre("Campagne Collecte EN_COURS Test " + UUID.randomUUID().toString().substring(0, 6))
                .statut(StatutCampagneCollecte.EN_COURS)
                .build();
        testCampagneEnCours.setActif(true);
        testCampagneEnCours.setDateCreation(LocalDateTime.now());
        // S'assurer que les champs numériques sont initialisés pour éviter NPE lors de .add()
        if (testCampagneEnCours.getMontantCollecteActuel() == null) {
            testCampagneEnCours.setMontantCollecteActuel(BigDecimal.ZERO);
        }
        if (testCampagneEnCours.getNombreDonateurs() == null) {
            testCampagneEnCours.setNombreDonateurs(0);
        }
        campagneCollecteRepository.persist(testCampagneEnCours);
    }

    @AfterEach
    @Transactional
    void cleanupTestData() {
        if (testCampagneEnCours != null && testCampagneEnCours.getId() != null) {
            contributionCollecteRepository.delete("campagne.id", testCampagneEnCours.getId());
            campagneCollecteRepository.deleteById(testCampagneEnCours.getId());
        }
        if (testCampagne != null && testCampagne.getId() != null) {
            contributionCollecteRepository.delete("campagne.id", testCampagne.getId());
            campagneCollecteRepository.deleteById(testCampagne.getId());
        }
        if (testOrganisation != null && testOrganisation.getId() != null) {
            organisationRepository.deleteById(testOrganisation.getId());
        }
    }

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

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

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

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "MEMBRE" })
    @DisplayName("POST contribuer sur campagne EN_COURS retourne 201")
    void contribuer_campagneEnCours_returns201() {
        String body = "{"
                + "\"montantSoutien\": 1000,"
                + "\"estAnonyme\": false"
                + "}";
        given()
                .contentType(ContentType.JSON)
                .body(body)
                .pathParam("id", testCampagneEnCours.getId())
                .when()
                .post("/api/v1/collectefonds/campagnes/{id}/contribuer")
                .then()
                .statusCode(201)
                .body("id", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "MEMBRE" })
    @DisplayName("POST contribuer avec ID inexistant retourne 4xx")
    void contribuer_idInexistant_returns4xx() {
        given()
                .contentType(ContentType.JSON)
                .body("{\"montant\": 1000}")
                .pathParam("id", UUID.randomUUID())
                .when()
                .post("/api/v1/collectefonds/campagnes/{id}/contribuer")
                .then()
                .statusCode(anyOf(equalTo(400), equalTo(404), equalTo(500)));
    }
}
