package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
import static org.assertj.core.api.Assertions.assertThat;

import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.service.MembreService;
import dev.lions.unionflow.server.service.OrganisationService;
import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.response.Response;
import jakarta.inject.Inject;
import java.time.LocalDate;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class DashboardResourceTest {

    @Inject
    OrganisationService organisationService;

    @Inject
    MembreService membreService;

    private Organisation testOrganisation;
    private Membre testMembre;

    @BeforeEach
    @TestTransaction
    void setup() {
        // Créer une organisation de test
        testOrganisation = new Organisation();
        testOrganisation.setNom("Lions Club Test Dashboard " + UUID.randomUUID());
        testOrganisation.setEmail("dash-test-" + UUID.randomUUID() + "@test.com");
        testOrganisation.setTypeOrganisation("CLUB");
        testOrganisation.setStatut("ACTIVE");
        testOrganisation.setActif(true);
        organisationService.creerOrganisation(testOrganisation, "admin@test.com");

        // Créer un membre de test
        testMembre = new Membre();
        testMembre.setPrenom("Test");
        testMembre.setNom("Dashboard");
        testMembre.setEmail("test.dashboard-" + UUID.randomUUID() + "@test.com");
        testMembre.setNumeroMembre("M-DASH-" + UUID.randomUUID().toString().substring(0, 8));
        testMembre.setDateNaissance(LocalDate.of(1990, 1, 1));
        testMembre.setStatutCompte("ACTIF");
        testMembre.setActif(true);
        membreService.creerMembre(testMembre);
    }

    @Test
    @TestTransaction
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/data avec données valides retourne 200 et JSON valide")
    void getDashboardData_validData_returns200WithValidJson() {
        Response response = given()
                .queryParam("organizationId", testOrganisation.getId().toString())
                .queryParam("userId", testMembre.getId().toString())
                .when()
                .get("/api/v1/dashboard/data")
                .then()
                .statusCode(200)
                .contentType("application/json")
                .extract()
                .response();

        // Vérifier que la réponse contient les champs attendus
        assertThat(response.jsonPath().getString("organizationId")).isNotNull();
        assertThat(response.jsonPath().getMap("stats")).isNotNull();
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/data sans paramètres retourne 400")
    void getDashboardData_missingParams_returns400() {
        given()
                .when()
                .get("/api/v1/dashboard/data")
                .then()
                .statusCode(400);
    }

    @Test
    @TestTransaction
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/stats avec données valides retourne 200 avec stats")
    void getDashboardStats_validData_returns200WithStats() {
        Response response = given()
                .queryParam("organizationId", testOrganisation.getId().toString())
                .queryParam("userId", testMembre.getId().toString())
                .when()
                .get("/api/v1/dashboard/stats")
                .then()
                .statusCode(200)
                .contentType("application/json")
                .extract()
                .response();

        // Vérifier que les stats contiennent les champs de base
        assertThat(response.jsonPath().getInt("totalMembers")).isGreaterThanOrEqualTo(0);
        assertThat(response.jsonPath().getInt("activeMembers")).isGreaterThanOrEqualTo(0);
    }

    @Test
    @TestTransaction
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/activities retourne 200 avec liste")
    void getDashboardActivities_returns200WithList() {
        Response response = given()
                .queryParam("organizationId", testOrganisation.getId().toString())
                .queryParam("userId", testMembre.getId().toString())
                .when()
                .get("/api/v1/dashboard/activities")
                .then()
                .statusCode(200)
                .contentType("application/json")
                .extract()
                .response();

        // Vérifier le wrapper avec activities, total, et limit
        assertThat(response.jsonPath().getList("activities")).isNotNull();
        assertThat(response.jsonPath().getInt("total")).isGreaterThanOrEqualTo(0);
        assertThat(response.jsonPath().getInt("limit")).isGreaterThan(0);
    }

    @Test
    @TestTransaction
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/events/upcoming retourne 200 avec liste")
    void getDashboardEventsUpcoming_returns200WithList() {
        Response response = given()
                .queryParam("organizationId", testOrganisation.getId().toString())
                .queryParam("userId", testMembre.getId().toString())
                .when()
                .get("/api/v1/dashboard/events/upcoming")
                .then()
                .statusCode(200)
                .contentType("application/json")
                .extract()
                .response();

        // Vérifier le wrapper avec events, total, et limit
        assertThat(response.jsonPath().getList("events")).isNotNull();
        assertThat(response.jsonPath().getInt("total")).isGreaterThanOrEqualTo(0);
        assertThat(response.jsonPath().getInt("limit")).isGreaterThan(0);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/health retourne 200 avec status UP")
    void getDashboardHealth_returns200WithStatusUp() {
        Response response = given()
                .when()
                .get("/api/v1/dashboard/health")
                .then()
                .statusCode(200)
                .contentType("application/json")
                .extract()
                .response();

        assertThat(response.jsonPath().getString("status")).isEqualTo("UP");
    }

    @Test
    @TestTransaction
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("POST /api/v1/dashboard/refresh retourne 200")
    void postDashboardRefresh_returns200() {
        given()
                .contentType("application/json")
                .queryParam("organizationId", testOrganisation.getId().toString())
                .queryParam("userId", testMembre.getId().toString())
                .when()
                .post("/api/v1/dashboard/refresh")
                .then()
                .statusCode(200);
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
    @DisplayName("GET /api/v1/dashboard/data avec organizationId invalide gère l'erreur")
    void getDashboardData_invalidOrgId_handlesError() {
        // Le service gère les UUID invalides gracieusement et peut retourner 200 ou 500
        given()
                .queryParam("organizationId", "invalid-uuid")
                .queryParam("userId", UUID.randomUUID().toString())
                .when()
                .get("/api/v1/dashboard/data")
                .then()
                .statusCode(anyOf(equalTo(200), equalTo(400), equalTo(500)));
    }
}
