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

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

import dev.lions.unionflow.server.entity.ProcesVerbal;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class ProcesVerbalServiceTest {

  private final ProcesVerbalService service = new ProcesVerbalService();

  private ProcesVerbal pv(String type, int convoques, int presents, int representes) {
    ProcesVerbal pv = ProcesVerbal.builder()
        .organisationId(UUID.randomUUID())
        .typeSeance(type)
        .titre("AG annuelle 2026")
        .dateConvocation(LocalDateTime.now().minusDays(15))
        .dateSeance(LocalDateTime.now())
        .nombreConvoques(convoques)
        .nombrePresents(presents)
        .nombreRepresentes(representes)
        .ordreDuJour("[]")
        .resolutions("[]")
        .build();
    pv.setId(UUID.randomUUID());
    return pv;
  }

  @Test
  @DisplayName("quorumRequisDefaut : AG ordinaire = 50%")
  void quorumAgOrdinaire() {
    assertThat(ProcesVerbalService.quorumRequisDefaut("AG_ORDINAIRE"))
        .isEqualByComparingTo(new BigDecimal("50.00"));
  }

  @Test
  @DisplayName("quorumRequisDefaut : AG extra/constitutive = 66.67%")
  void quorumAgExtra() {
    assertThat(ProcesVerbalService.quorumRequisDefaut("AG_EXTRAORDINAIRE"))
        .isEqualByComparingTo(new BigDecimal("66.67"));
    assertThat(ProcesVerbalService.quorumRequisDefaut("AG_CONSTITUTIVE"))
        .isEqualByComparingTo(new BigDecimal("66.67"));
  }

  @Test
  @DisplayName("calculerEtFixerQuorum : 60/100 → 60% atteint pour AG ordinaire")
  void quorumAtteint() {
    ProcesVerbal p = pv("AG_ORDINAIRE", 100, 50, 10);
    service.calculerEtFixerQuorum(p);
    assertThat(p.getQuorumCalculePct()).isEqualByComparingTo(new BigDecimal("60.00"));
    assertThat(p.isQuorumAtteint()).isTrue();
  }

  @Test
  @DisplayName("calculerEtFixerQuorum : 30/100 → 30% NON atteint pour AG ordinaire")
  void quorumNonAtteint() {
    ProcesVerbal p = pv("AG_ORDINAIRE", 100, 25, 5);
    service.calculerEtFixerQuorum(p);
    assertThat(p.getQuorumCalculePct()).isEqualByComparingTo(new BigDecimal("30.00"));
    assertThat(p.isQuorumAtteint()).isFalse();
  }

  @Test
  @DisplayName("calculerEtFixerQuorum : convoqués=0 → quorum 0% non atteint")
  void quorumConvoqueZero() {
    ProcesVerbal p = pv("AG_ORDINAIRE", 0, 0, 0);
    service.calculerEtFixerQuorum(p);
    assertThat(p.getQuorumCalculePct()).isEqualByComparingTo(BigDecimal.ZERO);
    assertThat(p.isQuorumAtteint()).isFalse();
  }

  @Test
  @DisplayName("calculerHash produit un SHA-256 de 64 caractères hexadécimaux")
  void hashFormat() {
    ProcesVerbal p = pv("CA", 12, 8, 0);
    service.calculerEtFixerQuorum(p);
    String hash = service.calculerHash(p);
    assertThat(hash).hasSize(64).matches("^[0-9a-f]{64}$");
  }

  @Test
  @DisplayName("calculerHash : même contenu → même hash (immutabilité)")
  void hashImmuabilite() {
    ProcesVerbal p1 = pv("CA", 10, 5, 2);
    p1.setId(UUID.fromString("00000000-0000-0000-0000-000000000001"));
    p1.setOrganisationId(UUID.fromString("00000000-0000-0000-0000-000000000002"));
    p1.setDateSeance(LocalDateTime.parse("2026-04-25T10:00:00"));
    service.calculerEtFixerQuorum(p1);

    ProcesVerbal p2 = pv("CA", 10, 5, 2);
    p2.setId(UUID.fromString("00000000-0000-0000-0000-000000000001"));
    p2.setOrganisationId(UUID.fromString("00000000-0000-0000-0000-000000000002"));
    p2.setDateSeance(LocalDateTime.parse("2026-04-25T10:00:00"));
    service.calculerEtFixerQuorum(p2);

    assertThat(service.calculerHash(p1)).isEqualTo(service.calculerHash(p2));
  }

  @Test
  @DisplayName("calculerHash : modification du titre → hash différent")
  void hashChangeOnModification() {
    ProcesVerbal p1 = pv("CA", 10, 5, 2);
    p1.setId(UUID.fromString("00000000-0000-0000-0000-000000000001"));
    String h1 = service.calculerHash(p1);

    p1.setTitre("Titre modifié");
    String h2 = service.calculerHash(p1);

    assertThat(h1).isNotEqualTo(h2);
  }
}
