package dev.lions.unionflow.server.entity;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

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

@DisplayName("ParametresLcbFt entity")
class ParametresLcbFtTest {

    // -------------------------------------------------------------------------
    // No-args constructor
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("no-args constructor creates instance with null fields")
    void noArgsConstructor_createsInstanceWithNullFields() {
        ParametresLcbFt params = new ParametresLcbFt();

        assertThat(params).isNotNull();
        assertThat(params.getOrganisation()).isNull();
        assertThat(params.getCodeDevise()).isNull();
        assertThat(params.getMontantSeuilJustification()).isNull();
        assertThat(params.getMontantSeuilValidationManuelle()).isNull();
    }

    // -------------------------------------------------------------------------
    // All-args constructor
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("all-args constructor sets all fields")
    void allArgsConstructor_setsAllFields() {
        Organisation org = new Organisation();
        BigDecimal seuilJustif = new BigDecimal("500000.0000");
        BigDecimal seuilValidation = new BigDecimal("2000000.0000");

        ParametresLcbFt params = new ParametresLcbFt(org, "XOF", seuilJustif, seuilValidation);

        assertThat(params.getOrganisation()).isSameAs(org);
        assertThat(params.getCodeDevise()).isEqualTo("XOF");
        assertThat(params.getMontantSeuilJustification()).isEqualByComparingTo(seuilJustif);
        assertThat(params.getMontantSeuilValidationManuelle()).isEqualByComparingTo(seuilValidation);
    }

    // -------------------------------------------------------------------------
    // Builder
    // -------------------------------------------------------------------------
    @Nested
    @DisplayName("Builder")
    class BuilderTests {

        @Test
        @DisplayName("builder sets organisation and thresholds")
        void builder_setsAllFields() {
            Organisation org = new Organisation();

            ParametresLcbFt params = ParametresLcbFt.builder()
                    .organisation(org)
                    .codeDevise("EUR")
                    .montantSeuilJustification(new BigDecimal("10000.0000"))
                    .montantSeuilValidationManuelle(new BigDecimal("50000.0000"))
                    .build();

            assertThat(params.getOrganisation()).isSameAs(org);
            assertThat(params.getCodeDevise()).isEqualTo("EUR");
            assertThat(params.getMontantSeuilJustification()).isEqualByComparingTo("10000.0000");
            assertThat(params.getMontantSeuilValidationManuelle()).isEqualByComparingTo("50000.0000");
        }

        @Test
        @DisplayName("builder with null organisation represents global parameters")
        void builder_nullOrganisationRepresentsGlobal() {
            ParametresLcbFt params = ParametresLcbFt.builder()
                    .organisation(null)
                    .codeDevise("XOF")
                    .montantSeuilJustification(new BigDecimal("1000000.0000"))
                    .build();

            assertThat(params.getOrganisation()).isNull();
            assertThat(params.getCodeDevise()).isEqualTo("XOF");
        }

        @Test
        @DisplayName("builder allows null montantSeuilValidationManuelle (optional field)")
        void builder_nullSeuilValidationManuelle_isAllowed() {
            ParametresLcbFt params = ParametresLcbFt.builder()
                    .codeDevise("XOF")
                    .montantSeuilJustification(BigDecimal.valueOf(500000))
                    .montantSeuilValidationManuelle(null)
                    .build();

            assertThat(params.getMontantSeuilValidationManuelle()).isNull();
        }
    }

    // -------------------------------------------------------------------------
    // Getters / Setters
    // -------------------------------------------------------------------------
    @Nested
    @DisplayName("Getters and Setters")
    class GettersSettersTests {

        @Test
        @DisplayName("setOrganisation / getOrganisation round-trips")
        void organisation_roundTrips() {
            Organisation org = new Organisation();
            ParametresLcbFt params = new ParametresLcbFt();
            params.setOrganisation(org);
            assertThat(params.getOrganisation()).isSameAs(org);
        }

        @Test
        @DisplayName("setCodeDevise / getCodeDevise round-trips")
        void codeDevise_roundTrips() {
            ParametresLcbFt params = new ParametresLcbFt();
            params.setCodeDevise("GNF");
            assertThat(params.getCodeDevise()).isEqualTo("GNF");
        }

        @Test
        @DisplayName("setMontantSeuilJustification / getMontantSeuilJustification round-trips")
        void montantSeuilJustification_roundTrips() {
            BigDecimal seuil = new BigDecimal("750000.0000");
            ParametresLcbFt params = new ParametresLcbFt();
            params.setMontantSeuilJustification(seuil);
            assertThat(params.getMontantSeuilJustification()).isEqualByComparingTo(seuil);
        }

        @Test
        @DisplayName("setMontantSeuilValidationManuelle / getMontantSeuilValidationManuelle round-trips")
        void montantSeuilValidationManuelle_roundTrips() {
            BigDecimal seuil = new BigDecimal("3000000.0000");
            ParametresLcbFt params = new ParametresLcbFt();
            params.setMontantSeuilValidationManuelle(seuil);
            assertThat(params.getMontantSeuilValidationManuelle()).isEqualByComparingTo(seuil);
        }

        @Test
        @DisplayName("setOrganisation to null (global params) is allowed")
        void organisation_canBeNull() {
            ParametresLcbFt params = new ParametresLcbFt();
            params.setOrganisation(null);
            assertThat(params.getOrganisation()).isNull();
        }
    }

    // -------------------------------------------------------------------------
    // UUID id (inherited from BaseEntity)
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("UUID id field is settable and gettable")
    void uuidId_settableAndGettable() {
        UUID id = UUID.randomUUID();
        ParametresLcbFt params = new ParametresLcbFt();
        params.setId(id);
        assertThat(params.getId()).isEqualTo(id);
    }

    // -------------------------------------------------------------------------
    // equals / hashCode
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("two instances with same id are equal")
    void equals_sameId_areEqual() {
        UUID id = UUID.randomUUID();
        ParametresLcbFt a = new ParametresLcbFt();
        a.setId(id);
        a.setCodeDevise("XOF");
        ParametresLcbFt b = new ParametresLcbFt();
        b.setId(id);
        b.setCodeDevise("XOF");

        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("two instances with different ids are not equal")
    void equals_differentIds_notEqual() {
        ParametresLcbFt a = new ParametresLcbFt();
        a.setId(UUID.randomUUID());
        ParametresLcbFt b = new ParametresLcbFt();
        b.setId(UUID.randomUUID());

        assertThat(a).isNotEqualTo(b);
    }

    // -------------------------------------------------------------------------
    // toString
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("toString contains codeDevise")
    void toString_containsCodeDevise() {
        ParametresLcbFt params = new ParametresLcbFt();
        params.setCodeDevise("XOF");
        assertThat(params.toString()).contains("XOF");
    }
}
