package org.dromara.web.config;

import org.dromara.common.security.config.SecurityConfig;
import org.dromara.common.security.config.properties.SecurityProperties;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.handler.MappedInterceptor;

import java.util.List;

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

@Tag("dev")
class SecurityExcludesConfigUnitTest {

    @Test
    void retrievePassword_isExcludedFromLoginAuthentication() throws Exception {
        List<PropertySource<?>> sources = new YamlPropertySourceLoader()
            .load("application", new ClassPathResource("application.yml"));
        MutablePropertySources propertySources = new MutablePropertySources();
        for (PropertySource<?> source : sources) {
            propertySources.addLast(source);
        }
        SecurityProperties properties = new Binder(ConfigurationPropertySources.from(propertySources))
            .bind("security", Bindable.of(SecurityProperties.class))
            .orElseThrow(() -> new AssertionError("security 配置未绑定"));

        assertThat(properties.getExcludes()).contains("/app/v1/retrievePassword");
    }

    @Test
    void securityInterceptor_alwaysExcludesRetrievePasswordWithoutExternalConfiguration() {
        SecurityProperties properties = new SecurityProperties();
        properties.setExcludes(new String[0]);
        SecurityConfig config = new SecurityConfig(properties);
        ReflectionTestUtils.setField(config, "ssePath", "/resource/sse");
        ExposedInterceptorRegistry registry = new ExposedInterceptorRegistry();

        config.addInterceptors(registry);

        MappedInterceptor interceptor = (MappedInterceptor) registry.getRegisteredInterceptors().get(0);
        assertThat(interceptor.getExcludePathPatterns()).contains("/app/v1/retrievePassword");
    }

    private static final class ExposedInterceptorRegistry extends InterceptorRegistry {

        private List<Object> getRegisteredInterceptors() {
            return super.getInterceptors();
        }
    }
}
