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.util.UUID;

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

@DisplayName("SystemConfigPersistence entity")
class SystemConfigPersistenceTest {

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

        assertThat(config).isNotNull();
        assertThat(config.getConfigKey()).isNull();
        assertThat(config.getConfigValue()).isNull();
    }

    // -------------------------------------------------------------------------
    // All-args constructor
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("all-args constructor sets configKey and configValue")
    void allArgsConstructor_setsFields() {
        SystemConfigPersistence config = new SystemConfigPersistence("smtp.host", "mail.example.com");

        assertThat(config.getConfigKey()).isEqualTo("smtp.host");
        assertThat(config.getConfigValue()).isEqualTo("mail.example.com");
    }

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

        @Test
        @DisplayName("builder sets configKey")
        void builder_setsConfigKey() {
            SystemConfigPersistence config = SystemConfigPersistence.builder()
                    .configKey("app.version")
                    .build();

            assertThat(config.getConfigKey()).isEqualTo("app.version");
        }

        @Test
        @DisplayName("builder sets configValue")
        void builder_setsConfigValue() {
            SystemConfigPersistence config = SystemConfigPersistence.builder()
                    .configValue("3.0.0")
                    .build();

            assertThat(config.getConfigValue()).isEqualTo("3.0.0");
        }

        @Test
        @DisplayName("builder sets both configKey and configValue")
        void builder_setsBothFields() {
            SystemConfigPersistence config = SystemConfigPersistence.builder()
                    .configKey("feature.kyc.enabled")
                    .configValue("true")
                    .build();

            assertThat(config.getConfigKey()).isEqualTo("feature.kyc.enabled");
            assertThat(config.getConfigValue()).isEqualTo("true");
        }

        @Test
        @DisplayName("builder allows null configValue (TEXT column is nullable)")
        void builder_nullConfigValue_isAllowed() {
            SystemConfigPersistence config = SystemConfigPersistence.builder()
                    .configKey("optional.setting")
                    .configValue(null)
                    .build();

            assertThat(config.getConfigKey()).isEqualTo("optional.setting");
            assertThat(config.getConfigValue()).isNull();
        }
    }

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

        @Test
        @DisplayName("setConfigKey / getConfigKey round-trips")
        void configKey_roundTrips() {
            SystemConfigPersistence config = new SystemConfigPersistence();
            config.setConfigKey("max.upload.size");
            assertThat(config.getConfigKey()).isEqualTo("max.upload.size");
        }

        @Test
        @DisplayName("setConfigValue / getConfigValue round-trips")
        void configValue_roundTrips() {
            SystemConfigPersistence config = new SystemConfigPersistence();
            config.setConfigValue("5242880");
            assertThat(config.getConfigValue()).isEqualTo("5242880");
        }

        @Test
        @DisplayName("configValue can store a JSON blob")
        void configValue_canStoreJson() {
            String json = "{\"enabled\":true,\"maxRetries\":3}";
            SystemConfigPersistence config = new SystemConfigPersistence();
            config.setConfigValue(json);
            assertThat(config.getConfigValue()).isEqualTo(json);
        }

        @Test
        @DisplayName("configValue can store a multiline text")
        void configValue_canStoreMultilineText() {
            String multiline = "line1\nline2\nline3";
            SystemConfigPersistence config = new SystemConfigPersistence();
            config.setConfigValue(multiline);
            assertThat(config.getConfigValue()).isEqualTo(multiline);
        }
    }

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

    // -------------------------------------------------------------------------
    // equals / hashCode  (Lombok @EqualsAndHashCode(callSuper=true))
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("two instances with same id are equal")
    void equals_sameId_areEqual() {
        UUID id = UUID.randomUUID();
        SystemConfigPersistence a = new SystemConfigPersistence("key", "val");
        a.setId(id);
        SystemConfigPersistence b = new SystemConfigPersistence("key", "val");
        b.setId(id);

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

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

        assertThat(a).isNotEqualTo(b);
    }

    // -------------------------------------------------------------------------
    // toString
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("toString contains configKey")
    void toString_containsConfigKey() {
        SystemConfigPersistence config = SystemConfigPersistence.builder()
                .configKey("smtp.port")
                .configValue("587")
                .build();

        assertThat(config.toString()).contains("smtp.port");
    }

    // -------------------------------------------------------------------------
    // Typical configuration keys scenario
    // -------------------------------------------------------------------------
    @Test
    @DisplayName("stores various typical configuration key-value pairs")
    void typicalConfigurations_storeCorrectly() {
        String[][] configs = {
            {"smtp.host",             "mail.example.com"},
            {"smtp.port",             "587"},
            {"feature.kyc.enabled",   "true"},
            {"max.upload.size.bytes", "5242880"},
            {"default.currency",      "XOF"}
        };

        for (String[] kv : configs) {
            SystemConfigPersistence config = SystemConfigPersistence.builder()
                    .configKey(kv[0])
                    .configValue(kv[1])
                    .build();
            assertThat(config.getConfigKey()).isEqualTo(kv[0]);
            assertThat(config.getConfigValue()).isEqualTo(kv[1]);
        }
    }
}
