package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;

import dev.lions.unionflow.server.api.dto.config.request.ParametresLcbFtRequest;
import dev.lions.unionflow.server.api.dto.config.response.ParametresLcbFtResponse;
import dev.lions.unionflow.server.service.ParametresLcbFtService;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.UUID;

/**
 * Tests d'intégration pour {@link ParametresLcbFtResource}.
 * Utilise @InjectMock pour couvrir les 4 méthodes : getParametres,
 * getSeuilJustification, saveOrUpdateParametres, et le record SeuilResponse.
 */
@QuarkusTest
class ParametresLcbFtResourceTest {

    @InjectMock
    ParametresLcbFtService parametresService;

    @BeforeEach
    void setupMocks() {
        ParametresLcbFtResponse response = ParametresLcbFtResponse.builder()
                .montantSeuilJustification(new BigDecimal("500000"))
                .montantSeuilValidationManuelle(new BigDecimal("1000000"))
                .codeDevise("XOF")
                .build();

        when(parametresService.getParametres(isNull(), any())).thenReturn(response);
        when(parametresService.getParametres(any(UUID.class), any())).thenReturn(response);

        when(parametresService.getSeuilJustification(isNull(), any())).thenReturn(new BigDecimal("500000"));
        when(parametresService.getSeuilJustification(any(UUID.class), any())).thenReturn(new BigDecimal("500000"));

        when(parametresService.saveOrUpdateParametres(any())).thenReturn(response);
    }

    // =========================================================================
    // GET /api/parametres-lcb-ft — getParametres
    // =========================================================================

    @Test
    @DisplayName("GET /api/parametres-lcb-ft sans organisationId retourne 200")
    void getParametres_withoutOrganisationId_returns200() {
        given()
                .queryParam("codeDevise", "XOF")
                .when()
                .get("/api/parametres-lcb-ft")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON);
    }

    @Test
    @DisplayName("GET /api/parametres-lcb-ft avec organisationId valide retourne 200")
    void getParametres_withOrganisationId_returns200() {
        UUID orgId = UUID.randomUUID();

        given()
                .queryParam("organisationId", orgId.toString())
                .queryParam("codeDevise", "XOF")
                .when()
                .get("/api/parametres-lcb-ft")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON);
    }

    @Test
    @DisplayName("GET /api/parametres-lcb-ft avec organisationId vide traite comme null")
    void getParametres_withBlankOrganisationId_returns200() {
        given()
                .queryParam("organisationId", "")
                .queryParam("codeDevise", "EUR")
                .when()
                .get("/api/parametres-lcb-ft")
                .then()
                .statusCode(200);
    }

    // =========================================================================
    // GET /api/parametres-lcb-ft/seuil-justification — getSeuilJustification
    // =========================================================================

    @Test
    @DisplayName("GET /api/parametres-lcb-ft/seuil-justification sans organisationId retourne 200")
    void getSeuilJustification_withoutOrganisationId_returns200() {
        given()
                .queryParam("codeDevise", "XOF")
                .when()
                .get("/api/parametres-lcb-ft/seuil-justification")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("montantSeuil", notNullValue())
                .body("codeDevise", equalTo("XOF"));
    }

    @Test
    @DisplayName("GET /api/parametres-lcb-ft/seuil-justification avec organisationId retourne 200")
    void getSeuilJustification_withOrganisationId_returns200() {
        UUID orgId = UUID.randomUUID();

        given()
                .queryParam("organisationId", orgId.toString())
                .queryParam("codeDevise", "XOF")
                .when()
                .get("/api/parametres-lcb-ft/seuil-justification")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("codeDevise", equalTo("XOF"));
    }

    @Test
    @DisplayName("GET /api/parametres-lcb-ft/seuil-justification avec devise par défaut XOF")
    void getSeuilJustification_defaultCurrency_returns200() {
        // Sans paramètre codeDevise → default = XOF
        given()
                .when()
                .get("/api/parametres-lcb-ft/seuil-justification")
                .then()
                .statusCode(200)
                .body("codeDevise", equalTo("XOF"));
    }

    @Test
    @DisplayName("GET /api/parametres-lcb-ft/seuil-justification avec organisationId vide traite comme null (missed branch isBlank)")
    void getSeuilJustification_withBlankOrganisationId_treatsAsNull() {
        // organisationId="" → isBlank() = true → orgId = null (missed branch of the ternary)
        given()
                .queryParam("organisationId", "")
                .queryParam("codeDevise", "XOF")
                .when()
                .get("/api/parametres-lcb-ft/seuil-justification")
                .then()
                .statusCode(200)
                .body("montantSeuil", notNullValue())
                .body("codeDevise", equalTo("XOF"));
    }

    // =========================================================================
    // POST /api/parametres-lcb-ft — saveOrUpdateParametres
    // =========================================================================

    @Test
    @TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN", "SUPER_ADMIN"})
    @DisplayName("POST /api/parametres-lcb-ft retourne 200 avec paramètres sauvegardés")
    void saveOrUpdateParametres_validRequest_returns200() {
        String body = """
                {
                  "montantSeuilJustification": 500000,
                  "montantSeuilValidationManuelle": 1000000,
                  "codeDevise": "XOF"
                }
                """;

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/parametres-lcb-ft")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON);
    }

    @Test
    @DisplayName("POST /api/parametres-lcb-ft sans auth retourne 401")
    void saveOrUpdateParametres_withoutAuth_returns401() {
        String body = """
                {
                  "montantSeuilJustification": 500000,
                  "montantSeuilValidationManuelle": 1000000,
                  "codeDevise": "XOF"
                }
                """;

        given()
                .contentType(ContentType.JSON)
                .body(body)
                .when()
                .post("/api/parametres-lcb-ft")
                .then()
                .statusCode(401);
    }
}
