package com.cameleer.server.app.alerting.config;

import com.cameleer.server.app.alerting.eval.PerKindCircuitBreaker;
import com.cameleer.server.app.alerting.metrics.AlertingMetrics;
import com.cameleer.server.app.alerting.storage.*;
import com.cameleer.server.core.alerting.AlertInstanceRepository;
import com.cameleer.server.core.alerting.AlertNotificationRepository;
import com.cameleer.server.core.alerting.AlertRuleRepository;
import com.cameleer.server.core.alerting.AlertSilenceRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import java.net.InetAddress;
import java.time.Clock;

@Configuration
@EnableConfigurationProperties(AlertingProperties.class)
public class AlertingBeanConfig {

    private static final Logger log = LoggerFactory.getLogger(AlertingBeanConfig.class);

    @Bean
    public AlertRuleRepository alertRuleRepository(JdbcTemplate jdbc, ObjectMapper om) {
        return new PostgresAlertRuleRepository(jdbc, om);
    }

    @Bean
    public AlertInstanceRepository alertInstanceRepository(JdbcTemplate jdbc, ObjectMapper om) {
        return new PostgresAlertInstanceRepository(jdbc, om);
    }

    @Bean
    public AlertSilenceRepository alertSilenceRepository(JdbcTemplate jdbc, ObjectMapper om) {
        return new PostgresAlertSilenceRepository(jdbc, om);
    }

    @Bean
    public AlertNotificationRepository alertNotificationRepository(JdbcTemplate jdbc, ObjectMapper om) {
        return new PostgresAlertNotificationRepository(jdbc, om);
    }

    @Bean
    public Clock alertingClock() {
        return Clock.systemDefaultZone();
    }

    @Bean("alertingInstanceId")
    public String alertingInstanceId() {
        String hostname;
        try {
            hostname = InetAddress.getLocalHost().getHostName();
        } catch (Exception e) {
            hostname = "unknown";
        }
        return hostname + ":" + ProcessHandle.current().pid();
    }

    @Bean
    public PerKindCircuitBreaker perKindCircuitBreaker(AlertingProperties props,
                                                       AlertingMetrics alertingMetrics) {
        if (props.evaluatorTickIntervalMs() != null
                && props.evaluatorTickIntervalMs() < 5000) {
            log.warn("cameleer.server.alerting.evaluatorTickIntervalMs={} is below the 5000 ms floor; clamping to 5000 ms",
                    props.evaluatorTickIntervalMs());
        }
        PerKindCircuitBreaker breaker = new PerKindCircuitBreaker(
                props.cbFailThreshold(),
                props.cbWindowSeconds(),
                props.cbCooldownSeconds());
        breaker.setMetrics(alertingMetrics);
        return breaker;
    }
}
