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

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

import dev.lions.unionflow.server.api.enums.tontine.FrequenceTour;
import dev.lions.unionflow.server.api.enums.tontine.StatutTontine;
import dev.lions.unionflow.server.api.enums.tontine.TypeTontine;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.tontine.Tontine;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.tontine.TontineRepository;
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 TontineResourceTest {

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    TontineRepository tontineRepository;

    private Organisation testOrganisation;
    private Tontine testTontine;

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

        testTontine = Tontine.builder()
                .nom("Tontine Test Resource")
                .organisation(testOrganisation)
                .typeTontine(TypeTontine.ROTATIVE_CLASSIQUE)
                .frequence(FrequenceTour.MENSUELLE)
                .statut(StatutTontine.PLANIFIEE)
                .montantMiseParTour(BigDecimal.valueOf(10000))
                .build();
        testTontine.setActif(true);
        testTontine.setDateCreation(LocalDateTime.now());
        tontineRepository.persist(testTontine);
    }

    @AfterEach
    @Transactional
    void cleanupTestData() {
        if (testTontine != null && testTontine.getId() != null) {
            tontineRepository.deleteById(testTontine.getId());
        }
        if (testOrganisation != null && testOrganisation.getId() != null) {
            organisationRepository.deleteById(testOrganisation.getId());
        }
    }

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

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

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

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "TONTINE_RESP" })
    @DisplayName("POST creerTontine avec organisation valide retourne 201")
    void creerTontine_valid_returns201() {
        String body = "{"
                + "\"nom\": \"Tontine POST Test\","
                + "\"organisationId\": \"" + testOrganisation.getId() + "\","
                + "\"typeTontine\": \"ROTATIVE_CLASSIQUE\","
                + "\"frequence\": \"MENSUELLE\","
                + "\"dateDebutPrevue\": \"2026-04-01\","
                + "\"montantMiseParTour\": 5000"
                + "}";
        String tontineId = given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/v1/tontines")
                .then()
                .statusCode(201)
                .body("id", notNullValue())
                .extract().path("id");

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

    @Transactional
    void cleanupTontine(UUID id) {
        tontineRepository.deleteById(id);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "TONTINE_RESP" })
    @DisplayName("PATCH changerStatut sans query param statut retourne 400")
    void changerStatut_sansStatut_returns400() {
        given()
                .pathParam("id", UUID.randomUUID())
                .when()
                .patch("/api/v1/tontines/{id}/statut")
                .then()
                .statusCode(400);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "TONTINE_RESP" })
    @DisplayName("PATCH changerStatut avec statut valide et ID inexistant retourne 404")
    void changerStatut_avecStatutValidEtIdInexistant_returns404() {
        given()
                .pathParam("id", UUID.randomUUID())
                .queryParam("statut", "EN_COURS")
                .when()
                .patch("/api/v1/tontines/{id}/statut")
                .then()
                .statusCode(404);
    }

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

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "TONTINE_RESP" })
    @DisplayName("PATCH changerStatut avec statut valide et ID existant retourne 200")
    void changerStatut_avecStatutValidEtIdExistant_returns200() {
        given()
                .pathParam("id", testTontine.getId())
                .queryParam("statut", "EN_COURS")
                .when()
                .patch("/api/v1/tontines/{id}/statut")
                .then()
                .statusCode(200)
                .body("id", notNullValue());
    }
}
