package dev.lions.unionflow.server.resource.mutuelle.epargne;

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.mutuelle.epargne.StatutCompteEpargne;
import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.mutuelle.epargne.CompteEpargne;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.mutuelle.epargne.CompteEpargneRepository;
import dev.lions.unionflow.server.repository.mutuelle.epargne.TransactionEpargneRepository;
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.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 TransactionEpargneResourceTest {

    @Inject
    MembreRepository membreRepository;

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    CompteEpargneRepository compteEpargneRepository;

    @Inject
    TransactionEpargneRepository transactionEpargneRepository;

    private Membre testMembre;
    private Organisation testOrganisation;
    private CompteEpargne testCompte;

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

        testMembre = Membre.builder()
                .numeroMembre("MBR-TXN-" + UUID.randomUUID().toString().substring(0, 6))
                .prenom("Pierre")
                .nom("Transaction")
                .email("txn-res-" + UUID.randomUUID() + "@test.com")
                .dateNaissance(LocalDate.of(1988, 7, 10))
                .build();
        testMembre.setActif(true);
        testMembre.setDateCreation(LocalDateTime.now());
        membreRepository.persist(testMembre);

        testCompte = CompteEpargne.builder()
                .membre(testMembre)
                .organisation(testOrganisation)
                .numeroCompte("CPT-TXN-" + UUID.randomUUID().toString().substring(0, 8))
                .typeCompte(TypeCompteEpargne.EPARGNE_LIBRE)
                .soldeActuel(BigDecimal.valueOf(100000))
                .statut(StatutCompteEpargne.ACTIF)
                .dateOuverture(LocalDate.now())
                .build();
        testCompte.setActif(true);
        testCompte.setDateCreation(LocalDateTime.now());
        compteEpargneRepository.persist(testCompte);
    }

    @AfterEach
    @Transactional
    void cleanupTestData() {
        // Delete transactions first (FK constraint)
        transactionEpargneRepository.delete("compte.id = ?1", testCompte.getId());
        if (testCompte != null && testCompte.getId() != null) {
            compteEpargneRepository.deleteById(testCompte.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", "MUTUELLE_RESP" })
    @DisplayName("GET /api/v1/epargne/transactions/compte/{id} retourne 200")
    void getTransactionsByCompte_returns200() {
        given()
                .pathParam("compteId", UUID.randomUUID())
                .when()
                .get("/api/v1/epargne/transactions/compte/{compteId}")
                .then()
                .statusCode(200)
                .body("$", notNullValue());
    }

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN", "ADMIN_ORGANISATION", "MUTUELLE_RESP", "MEMBRE" })
    @DisplayName("POST /api/v1/epargne/transactions avec compte ACTIF retourne 201")
    void executerTransaction_valid_returns201() {
        String body = "{"
                + "\"compteId\": \"" + testCompte.getId() + "\","
                + "\"typeTransaction\": \"DEPOT\","
                + "\"montant\": 5000,"
                + "\"motif\": \"Dépôt test\""
                + "}";
        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/v1/epargne/transactions")
                .then()
                .statusCode(201)
                .body("id", notNullValue());
    }

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

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