package com.magistr.app.config.tenant.health;

import com.magistr.app.config.tenant.TenantConfig;
import com.magistr.app.config.tenant.TenantRoutingDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.servlet.MockMvc;

import java.time.Clock;
import java.time.Duration;
import java.util.List;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest(
        classes = HealthProbeEndpointIntegrationTest.ProbeApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.MOCK,
        properties = {
                "management.endpoints.web.exposure.include=health",
                "management.endpoint.health.probes.enabled=true",
                "management.endpoint.health.group.liveness.include=livenessState",
                "management.endpoint.health.group.readiness.include=readinessState,tenantReadiness",
                "management.endpoint.health.show-details=never",
                "management.endpoint.health.show-components=never"
        }
)
@AutoConfigureMockMvc
class HealthProbeEndpointIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private TenantReadinessRegistry readinessRegistry;

    @Test
    void отказTenantБдСнимаетReadinessНоНеLiveness() throws Exception {
        TenantConfig tenant = new TenantConfig(
                "Тестовый университет",
                "test",
                "jdbc:postgresql://database/test",
                "user",
                "secret"
        );
        readinessRegistry.replaceDesired(List.of(tenant));
        readinessRegistry.markMigrationFailed(tenant);

        mockMvc.perform(get("/actuator/health/readiness").header("Host", "10.20.30.40"))
                .andExpect(status().isServiceUnavailable())
                .andExpect(jsonPath("$.status").value("DOWN"))
                .andExpect(jsonPath("$.components").doesNotExist());

        mockMvc.perform(get("/actuator/health/liveness").header("Host", "10.20.30.40"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.status").value("UP"))
                .andExpect(jsonPath("$.components").doesNotExist());

        readinessRegistry.markMigrationSucceeded(tenant);
        readinessRegistry.markConnectivity(tenant.getDomain(), true);

        mockMvc.perform(get("/actuator/health/readiness").header("Host", "10.20.30.40"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.status").value("UP"));
    }

    @SpringBootConfiguration
    @EnableAutoConfiguration(exclude = {
            DataSourceAutoConfiguration.class,
            HibernateJpaAutoConfiguration.class
    })
    static class ProbeApplication {

        @Bean
        TenantReadinessRegistry tenantReadinessRegistry() {
            return new TenantReadinessRegistry();
        }

        @Bean
        TenantDatabaseHealthMonitor tenantDatabaseHealthMonitor(TenantReadinessRegistry registry) {
            return new TenantDatabaseHealthMonitor(
                    registry,
                    new TenantRoutingDataSource(),
                    1,
                    Duration.ofSeconds(1),
                    Duration.ofSeconds(30),
                    Clock.systemUTC()
            );
        }

        @Bean("tenantReadiness")
        TenantReadinessHealthIndicator tenantReadiness(
                TenantReadinessRegistry registry,
                TenantDatabaseHealthMonitor monitor) {
            return new TenantReadinessHealthIndicator(registry, monitor);
        }
    }
}
