package ru.yandex.qe.dispenser.quartz.monitoring;

import java.util.concurrent.ConcurrentHashMap;

import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.TriggerListener;

import ru.yandex.qe.dispenser.solomon.SolomonHolder;
import ru.yandex.monlib.metrics.labels.Labels;
import ru.yandex.monlib.metrics.primitives.Rate;
import ru.yandex.monlib.metrics.registry.MetricRegistry;

public class MonitoringTriggerListener implements TriggerListener {

    private static final String MISFIRE_RATE = "scheduler.misfire_rate";
    private static final String SCHEDULER = "scheduler";
    private static final String JOB = "job";
    private static final String TRIGGER = "trigger";

    private final String schedulerName;
    private final String listenerName;
    private final MetricRegistry rootRegistry;
    private final ConcurrentHashMap<TriggerKey, Rate> misfireRates = new ConcurrentHashMap<>();

    private boolean aggregateByGroup = false;

    public MonitoringTriggerListener(final String schedulerName, final SolomonHolder solomonHolder) {
        this.schedulerName = schedulerName;
        this.listenerName = "MonitoringTriggerListener_" + schedulerName;
        this.rootRegistry = solomonHolder.getRootRegistry();
    }

    public MonitoringTriggerListener(final String schedulerName, final SolomonHolder solomonHolder, final boolean aggregateByGroup) {
        this(schedulerName, solomonHolder);
        this.aggregateByGroup = aggregateByGroup;
    }

    @Override
    public String getName() {
        return listenerName;
    }

    @Override
    public void triggerFired(final Trigger trigger, final JobExecutionContext context) {
    }

    @Override
    public boolean vetoJobExecution(final Trigger trigger, final JobExecutionContext context) {
        return false;
    }

    @Override
    public void triggerMisfired(final Trigger trigger) {
        final TriggerKey triggerKey = aggregateByGroup
                ? new TriggerKey("", trigger.getKey().getGroup())
                : trigger.getKey();
        final JobKey jobKey = aggregateByGroup
                ? new JobKey("", trigger.getJobKey().getGroup())
                : trigger.getJobKey();
        final String triggerName = triggerKey.getGroup() + "." + triggerKey.getName();
        final String jobName = jobKey.getGroup() + "." + jobKey.getName();
        final Rate rate = misfireRates.computeIfAbsent(triggerKey, k -> rootRegistry.rate(MISFIRE_RATE,
                Labels.of(SCHEDULER, schedulerName, JOB, jobName, TRIGGER, triggerName)));
        rate.inc();
    }

    @Override
    public void triggerComplete(final Trigger trigger, final JobExecutionContext context, final Trigger.CompletedExecutionInstruction triggerInstructionCode) {
    }

}
