package com.magistr.app.config.auth;

import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.mock.env.MockEnvironment;

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

class JwtSecurityStartupValidatorTest {

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withUserConfiguration(JwtValidationTestConfiguration.class)
            .withPropertyValues("spring.profiles.active=production");

    @Test
    void productionContextDoesNotStartWithoutSecret() {
        contextRunner
                .withPropertyValues("app.jwt.refresh-cookie-secure=true")
                .run(context -> {
                    assertThat(context).hasFailed();
                    assertThat(context.getStartupFailure())
                            .hasRootCauseMessage("JWT_SECRET обязателен и не может быть пустым");
                });
    }

    @Test
    void productionContextDoesNotStartWithPlaceholderSecret() {
        String placeholder = String.join("-", "change", "this", "production", "value") + "x".repeat(32);

        contextRunner
                .withPropertyValues(
                        "app.jwt.secret=" + placeholder,
                        "app.jwt.refresh-cookie-secure=true"
                )
                .run(context -> {
                    assertThat(context).hasFailed();
                    assertThat(context.getStartupFailure())
                            .hasRootCauseMessage(
                                    "JWT_SECRET содержит известное небезопасное или шаблонное значение"
                            );
                });
    }

    @Test
    void productionContextStartsWithSecureConfiguration() {
        contextRunner
                .withPropertyValues(
                        "app.jwt.secret=" + "A1b2C3d4".repeat(6),
                        "app.jwt.refresh-cookie-secure=true"
                )
                .run(context -> assertThat(context).hasNotFailed());
    }

    @Test
    void stopsStartupForInsecureProductionCookie() {
        JwtProperties properties = properties(false);
        MockEnvironment environment = new MockEnvironment();
        environment.setActiveProfiles("production");

        JwtSecurityStartupValidator validator = new JwtSecurityStartupValidator(properties, environment);

        assertThatThrownBy(validator::validate)
                .isInstanceOf(IllegalStateException.class)
                .hasMessage("В production-профиле JWT_REFRESH_COOKIE_SECURE должен иметь значение true");
    }

    @Test
    void acceptsSecureProductionConfiguration() {
        JwtProperties properties = properties(true);
        MockEnvironment environment = new MockEnvironment();
        environment.setActiveProfiles("production");

        JwtSecurityStartupValidator validator = new JwtSecurityStartupValidator(properties, environment);

        assertThatCode(validator::validate).doesNotThrowAnyException();
    }

    private JwtProperties properties(boolean secureCookie) {
        JwtProperties properties = new JwtProperties();
        properties.setSecret("A1b2C3d4".repeat(6));
        properties.setRefreshCookieSecure(secureCookie);
        return properties;
    }

    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(JwtProperties.class)
    static class JwtValidationTestConfiguration {

        @Bean
        JwtSecurityStartupValidator jwtSecurityStartupValidator(JwtProperties properties,
                                                                Environment environment) {
            return new JwtSecurityStartupValidator(properties, environment);
        }
    }
}
