package dev.lions.unionflow.server.service.diaspora;

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

import dev.lions.unionflow.server.entity.Devise;
import dev.lions.unionflow.server.entity.KycDossier;
import dev.lions.unionflow.server.entity.Membre;
import java.math.BigDecimal;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class KycDiasporaServiceTest {

  private final KycDiasporaService service = new KycDiasporaService();

  // ── validerCoherence ──────────────────────────────────────────────────────

  @Test
  @DisplayName("Membre null → erreur")
  void coherence_null() {
    assertThat(service.validerCoherence(null)).contains("Membre null");
  }

  @Test
  @DisplayName("Diaspora avec passeport et FRA → OK")
  void coherence_diasporaValide() {
    Membre m = Membre.builder()
        .estDiaspora(true)
        .paysResidence("FRA")
        .numeroPasseport("12AB34567")
        .build();
    assertThat(service.validerCoherence(m)).isEmpty();
  }

  @Test
  @DisplayName("Diaspora sans passeport → erreur")
  void coherence_diasporaSansPasseport() {
    Membre m = Membre.builder()
        .estDiaspora(true)
        .paysResidence("FRA")
        .build();
    assertThat(service.validerCoherence(m))
        .anyMatch(e -> e.contains("numero_passeport obligatoire"));
  }

  @Test
  @DisplayName("Diaspora avec pays UEMOA → erreur")
  void coherence_diasporaPaysUemoa() {
    Membre m = Membre.builder()
        .estDiaspora(true)
        .paysResidence("CIV")
        .numeroPasseport("CI1234567")
        .build();
    assertThat(service.validerCoherence(m))
        .anyMatch(e -> e.contains("ne peut être un pays UEMOA"));
  }

  @Test
  @DisplayName("Non-diaspora avec pays hors UEMOA → erreur")
  void coherence_nonDiasporaPaysEtranger() {
    Membre m = Membre.builder()
        .estDiaspora(false)
        .paysResidence("USA")
        .build();
    assertThat(service.validerCoherence(m))
        .anyMatch(e -> e.contains("Incohérence"));
  }

  @Test
  @DisplayName("Passeport format invalide → erreur")
  void coherence_passeportInvalide() {
    Membre m = Membre.builder()
        .estDiaspora(true)
        .paysResidence("FRA")
        .numeroPasseport("xx") // trop court + minuscules
        .build();
    assertThat(service.validerCoherence(m))
        .anyMatch(e -> e.contains("numero_passeport : format invalide"));
  }

  // ── determinerNiveauDueDiligence ─────────────────────────────────────────

  @Test
  @DisplayName("PEP → RENFORCE")
  void due_pep() {
    Membre m = Membre.builder().estDiaspora(false).build();
    KycDossier k = KycDossier.builder().estPep(true).build();
    assertThat(service.determinerNiveauDueDiligence(m, k)).isEqualTo("RENFORCE");
  }

  @Test
  @DisplayName("Diaspora France → STANDARD")
  void due_diasporaFra() {
    Membre m = Membre.builder().estDiaspora(true).paysResidence("FRA").build();
    KycDossier k = KycDossier.builder().estPep(false).build();
    assertThat(service.determinerNiveauDueDiligence(m, k)).isEqualTo("STANDARD");
  }

  @Test
  @DisplayName("Diaspora pays grey-list FATF → RENFORCE")
  void due_diasporaGreyList() {
    Membre m = Membre.builder().estDiaspora(true).paysResidence("PHL").build();
    KycDossier k = KycDossier.builder().estPep(false).build();
    assertThat(service.determinerNiveauDueDiligence(m, k)).isEqualTo("RENFORCE");
  }

  @Test
  @DisplayName("Diaspora pays inconnu (ni sécurisé ni grey-list) → RENFORCE")
  void due_diasporaPaysInconnu() {
    Membre m = Membre.builder().estDiaspora(true).paysResidence("KAZ").build();
    KycDossier k = KycDossier.builder().estPep(false).build();
    assertThat(service.determinerNiveauDueDiligence(m, k)).isEqualTo("RENFORCE");
  }

  @Test
  @DisplayName("Résident UEMOA + non PEP → STANDARD")
  void due_residentUemoa() {
    Membre m = Membre.builder().estDiaspora(false).build();
    KycDossier k = KycDossier.builder().estPep(false).build();
    assertThat(service.determinerNiveauDueDiligence(m, k)).isEqualTo("STANDARD");
  }

  @Test
  @DisplayName("Membre ou KYC null → STANDARD défaut")
  void due_null() {
    assertThat(service.determinerNiveauDueDiligence(null, null)).isEqualTo("STANDARD");
  }

  // ── depasseSeuilAmlInternational ─────────────────────────────────────────

  @Test
  @DisplayName("EUR ≥ 1000 → dépasse seuil")
  void seuil_eurAuDessus() {
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("1500"), Devise.EUR, null))
        .isTrue();
  }

  @Test
  @DisplayName("EUR < 1000 → ne dépasse pas")
  void seuil_eurEnDessous() {
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("500"), Devise.EUR, null))
        .isFalse();
  }

  @Test
  @DisplayName("USD avec taux fourni — calcul correct")
  void seuil_usdAvecTaux() {
    // 1500 USD × 0.92 = 1380 EUR ≥ 1000
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("1500"), Devise.USD,
        new BigDecimal("0.92"))).isTrue();
    // 500 USD × 0.92 = 460 EUR < 1000
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("500"), Devise.USD,
        new BigDecimal("0.92"))).isFalse();
  }

  @Test
  @DisplayName("Sans taux disponible → considéré dépassé (prudence)")
  void seuil_sansTauxPrudence() {
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("100"), Devise.GBP, null))
        .isTrue();
  }

  @Test
  @DisplayName("XOF (devise locale) → ne déclenche pas reporting international")
  void seuil_xof() {
    assertThat(service.depasseSeuilAmlInternational(new BigDecimal("100000000"),
        Devise.XOF, null)).isFalse();
  }

  @Test
  @DisplayName("Montant null → false")
  void seuil_montantNull() {
    assertThat(service.depasseSeuilAmlInternational(null, Devise.EUR, null)).isFalse();
  }

  @Test
  @DisplayName("Devise null → false")
  void seuil_deviseNull() {
    assertThat(service.depasseSeuilAmlInternational(BigDecimal.TEN, null, null)).isFalse();
  }
}
