package cz.senslog.analytics.module;

import cz.senslog.analytics.domain.*;
import cz.senslog.analytics.module.api.CollectorModule;
import cz.senslog.analytics.repository.AnalyticsRepository;
import cz.senslog.analytics.utils.validator.ThresholdChecker;
import cz.senslog.analytics.utils.validator.Validator;
import cz.senslog.analytics.utils.validator.domain.ViolationReport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;

import static cz.senslog.analytics.domain.AttributeType.*;

public class DoubleStatisticsModule extends CollectorModule {

    private static final Logger logger = LogManager.getLogger(DoubleStatisticsModule.class);

    private static final String DEFAULT_GROUP_NAME = "unknown";
    private static final Validator<DoubleStatistics> validator;

    private ThresholdChecker<DoubleStatistics> thresholdChecker;

    static {
        validator = Validator.<DoubleStatistics>create()
                .addMapping(MIN, s -> s::min)
                .addMapping(MAX, s -> s::max)
                .addMapping(AVG, s -> s::average);
    }

    public DoubleStatisticsModule(AnalyticsRepository configRepo) {
        super(CollectorType.DOUBLE, configRepo);
    }

    @Override
    protected void init() {
        thresholdChecker = new ThresholdChecker<>(thresholds(), validator, this::notifyIfViolation, true);
    }

    private void notifyIfViolation(ViolationReport report) {
        Optional<AnalyticGroup> source = Optional.ofNullable(groups().get(report.datasourceId()));
        String sourceName = source.map(AnalyticGroup::name).orElse(DEFAULT_GROUP_NAME);
        notify(new ThresholdViolationAlert(type().name(), report.datasourceId(), sourceName, report.message(), report.timestamp()));
    }

    private Stream<StatisticRecord> mapToStatisticRecord(DoubleStatistics st) {
        AnalyticGroup analyticGroup = groups().get(st.datasourceId());
        return Stream.of(
            new StatisticRecord(0, st.datasourceId(), MIN, st.min(), analyticGroup.interval(), st.timestamp()),
            new StatisticRecord(0, st.datasourceId(), AVG, st.average(), analyticGroup.interval(), st.timestamp()),
            new StatisticRecord(0, st.datasourceId(), MAX, st.max(), analyticGroup.interval(), st.timestamp())
        );
    }

    @Override
    protected void handle(Collection<DoubleStatistics> aggregations) {
        aggregations.stream()
                .filter(thresholdChecker::check)
                .flatMap(this::mapToStatisticRecord)
                .forEach(this::persist);
    }
}