package stirling.software.saas.config;

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

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

/**
 * Unit tests for {@link SupabaseConfigurationProperties}.
 *
 * <p>A plain {@code @Data} config bean. Covers the Lombok getters/setters round-trip, the {@code
 * clockSkewSeconds} default, and both decision methods ({@code isJwtConfigured}, {@code
 * isEdgeFunctionConfigured}) across their null/blank/populated branches.
 */
class SupabaseConfigurationPropertiesTest {

    @Nested
    @DisplayName("defaults and accessors")
    class DefaultsAndAccessors {

        @Test
        @DisplayName("clockSkewSeconds defaults to 120")
        void clockSkewDefault() {
            assertThat(new SupabaseConfigurationProperties().getClockSkewSeconds()).isEqualTo(120L);
        }

        @Test
        @DisplayName("all fields round-trip through getters and setters")
        void gettersAndSetters() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();

            props.setIssuer("https://abc.supabase.co/auth/v1");
            props.setExpectedAud("authenticated");
            props.setClockSkewSeconds(300L);
            props.setEdgeFunctionUrl("https://abc.supabase.co/functions/v1");
            props.setEdgeFunctionSecret("shhh");

            assertThat(props.getIssuer()).isEqualTo("https://abc.supabase.co/auth/v1");
            assertThat(props.getExpectedAud()).isEqualTo("authenticated");
            assertThat(props.getClockSkewSeconds()).isEqualTo(300L);
            assertThat(props.getEdgeFunctionUrl())
                    .isEqualTo("https://abc.supabase.co/functions/v1");
            assertThat(props.getEdgeFunctionSecret()).isEqualTo("shhh");
        }

        @Test
        @DisplayName("equals/hashCode/toString are generated by Lombok @Data")
        void lombokDataContracts() {
            SupabaseConfigurationProperties a = new SupabaseConfigurationProperties();
            a.setIssuer("iss");
            SupabaseConfigurationProperties b = new SupabaseConfigurationProperties();
            b.setIssuer("iss");

            assertThat(a).isEqualTo(b).hasSameHashCodeAs(b);
            assertThat(a.toString()).contains("iss");
        }
    }

    @Nested
    @DisplayName("isJwtConfigured")
    class IsJwtConfigured {

        @Test
        @DisplayName("false when issuer is null")
        void nullIssuer() {
            assertThat(new SupabaseConfigurationProperties().isJwtConfigured()).isFalse();
        }

        @Test
        @DisplayName("false when issuer is blank")
        void blankIssuer() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setIssuer("   ");
            assertThat(props.isJwtConfigured()).isFalse();
        }

        @Test
        @DisplayName("true when issuer is set")
        void issuerSet() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setIssuer("https://abc.supabase.co/auth/v1");
            assertThat(props.isJwtConfigured()).isTrue();
        }
    }

    @Nested
    @DisplayName("isEdgeFunctionConfigured")
    class IsEdgeFunctionConfigured {

        @Test
        @DisplayName("false when both url and secret are null")
        void bothNull() {
            assertThat(new SupabaseConfigurationProperties().isEdgeFunctionConfigured()).isFalse();
        }

        @Test
        @DisplayName("false when only the url is set")
        void urlOnly() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setEdgeFunctionUrl("https://abc.supabase.co/functions/v1");
            assertThat(props.isEdgeFunctionConfigured()).isFalse();
        }

        @Test
        @DisplayName("false when only the secret is set")
        void secretOnly() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setEdgeFunctionSecret("shhh");
            assertThat(props.isEdgeFunctionConfigured()).isFalse();
        }

        @Test
        @DisplayName("false when url is set but secret is blank")
        void urlSetSecretBlank() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setEdgeFunctionUrl("https://abc.supabase.co/functions/v1");
            props.setEdgeFunctionSecret("   ");
            assertThat(props.isEdgeFunctionConfigured()).isFalse();
        }

        @Test
        @DisplayName("false when url is blank but secret is set")
        void urlBlankSecretSet() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setEdgeFunctionUrl("   ");
            props.setEdgeFunctionSecret("shhh");
            assertThat(props.isEdgeFunctionConfigured()).isFalse();
        }

        @Test
        @DisplayName("true when both url and secret are set")
        void bothSet() {
            SupabaseConfigurationProperties props = new SupabaseConfigurationProperties();
            props.setEdgeFunctionUrl("https://abc.supabase.co/functions/v1");
            props.setEdgeFunctionSecret("shhh");
            assertThat(props.isEdgeFunctionConfigured()).isTrue();
        }
    }
}
