package cz.senslog.analytics.module;

import cz.senslog.analytics.domain.*;
import cz.senslog.analytics.module.api.CollectorModule;
import cz.senslog.analytics.repository.ConfigurationRepository;
import cz.senslog.analytics.repository.AnalyticsDataRepository;
import cz.senslog.analytics.utils.validator.ThresholdChecker;
import cz.senslog.analytics.utils.validator.Validator;
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;

public class DoubleStatisticsModule extends CollectorModule {

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

    private static final Validator<DoubleStatistics> validator;

    private ThresholdChecker<DoubleStatistics> thresholdChecker;

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

    public DoubleStatisticsModule(ConfigurationRepository configRepo, AnalyticsDataRepository statisticsRep) {
        super(CollectorType.DOUBLE, configRepo, statisticsRep);
    }

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

    private void notifyIfViolation(ViolationReport report) {
        Optional<Group> source = Optional.ofNullable(groups().get(report.sourceId()));
        String sourceName = source.map(Group::name).orElse("unknown");
        notify(new ThresholdViolationNotification(type().name(), report.sourceId(), sourceName, report.violatedData(), report.timestamp()));
    }

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

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