package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.enums.membre.NiveauRisqueKyc;
import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite;
import dev.lions.unionflow.server.entity.KycDossier;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Tests unitaires du moteur de scoring risque KYC/AML.
 * Les méthodes transactionnelles nécessitent @QuarkusTest (tests d'intégration P2.4).
 */
class KycAmlServiceTest {

    private final KycAmlService service = new KycAmlService();

    private KycDossier dossierComplet() {
        return KycDossier.builder()
                .typePiece(TypePieceIdentite.CNI)
                .numeroPiece("CI-12345678")
                .dateExpirationPiece(LocalDate.now().plusYears(2))
                .pieceIdentiteRectoFileId("file-recto-001")
                .pieceIdentiteVersoFileId("file-verso-001")
                .justifDomicileFileId("file-domicile-001")
                .estPep(false)
                .nationalite("CI")
                .build();
    }

    @Test
    @DisplayName("Score 0 — dossier complet, non-PEP, nationalité UEMOA, pièce valide")
    void score_dossierParfait_zero() {
        assertThat(service.calculerScore(dossierComplet())).isEqualTo(0);
    }

    @Test
    @DisplayName("Score +40 — PEP")
    void score_pep_plusQuarante() {
        KycDossier d = dossierComplet();
        d.setEstPep(true);
        assertThat(service.calculerScore(d)).isEqualTo(40);
    }

    @Test
    @DisplayName("Score +20 — pièce expirée")
    void score_pieceExpiree_plusVingt() {
        KycDossier d = dossierComplet();
        d.setDateExpirationPiece(LocalDate.now().minusDays(1));
        assertThat(service.calculerScore(d)).isEqualTo(20);
    }

    @Test
    @DisplayName("Score +15 — justif domicile manquant")
    void score_justifDomicileManquant_plusQuinze() {
        KycDossier d = dossierComplet();
        d.setJustifDomicileFileId(null);
        assertThat(service.calculerScore(d)).isEqualTo(15);
    }

    @Test
    @DisplayName("Score +15 — pièce recto manquante")
    void score_rectoManquant_plusQuinze() {
        KycDossier d = dossierComplet();
        d.setPieceIdentiteRectoFileId(null);
        assertThat(service.calculerScore(d)).isEqualTo(15);
    }

    @Test
    @DisplayName("Score +10 — nationalité hors UEMOA")
    void score_horsUemoa_plusDix() {
        KycDossier d = dossierComplet();
        d.setNationalite("FR");
        assertThat(service.calculerScore(d)).isEqualTo(10);
    }

    @Test
    @DisplayName("Score plafonné à 100")
    void score_toutFaux_plafonneCent() {
        KycDossier d = KycDossier.builder()
                .typePiece(TypePieceIdentite.PASSEPORT)
                .numeroPiece("P-999")
                .dateExpirationPiece(LocalDate.now().minusDays(1)) // +20
                .estPep(true)                                       // +40
                .nationalite("CN")                                  // +10
                .build();
        // justif domicile null = +15, recto/verso null = +15 → total 100
        int score = service.calculerScore(d);
        assertThat(score).isEqualTo(100);
    }

    @Test
    @DisplayName("NiveauRisqueKyc.fromScore — score 0 → FAIBLE")
    void fromScore_zero_faible() {
        assertThat(NiveauRisqueKyc.fromScore(0)).isEqualTo(NiveauRisqueKyc.FAIBLE);
    }

    @Test
    @DisplayName("NiveauRisqueKyc.fromScore — score 40 → MOYEN")
    void fromScore_40_moyen() {
        assertThat(NiveauRisqueKyc.fromScore(40)).isEqualTo(NiveauRisqueKyc.MOYEN);
    }

    @Test
    @DisplayName("NiveauRisqueKyc.fromScore — score 70 → ELEVE")
    void fromScore_70_eleve() {
        assertThat(NiveauRisqueKyc.fromScore(70)).isEqualTo(NiveauRisqueKyc.ELEVE);
    }

    @Test
    @DisplayName("NiveauRisqueKyc.fromScore — score 90 → CRITIQUE")
    void fromScore_90_critique() {
        assertThat(NiveauRisqueKyc.fromScore(90)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
    }

    @Test
    @DisplayName("NiveauRisqueKyc.fromScore — score 100 → CRITIQUE")
    void fromScore_cent_critique() {
        assertThat(NiveauRisqueKyc.fromScore(100)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
    }

    @Test
    @DisplayName("isPieceExpiree — date future → false")
    void isPieceExpiree_dateFuture_false() {
        KycDossier d = dossierComplet();
        assertThat(d.isPieceExpiree()).isFalse();
    }

    @Test
    @DisplayName("isPieceExpiree — date passée → true")
    void isPieceExpiree_datePassee_true() {
        KycDossier d = dossierComplet();
        d.setDateExpirationPiece(LocalDate.now().minusDays(1));
        assertThat(d.isPieceExpiree()).isTrue();
    }

    @Test
    @DisplayName("isPieceExpiree — date null → false")
    void isPieceExpiree_null_false() {
        KycDossier d = dossierComplet();
        d.setDateExpirationPiece(null);
        assertThat(d.isPieceExpiree()).isFalse();
    }
}
