package ru.yandex.webmaster3.worker.task.periodic;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.solomon.metric.SolomonKey;
import ru.yandex.webmaster3.core.solomon.metric.SolomonMetricRegistry;
import ru.yandex.webmaster3.core.solomon.metric.SolomonTimer;
import ru.yandex.webmaster3.core.solomon.metric.SolomonTimerConfiguration;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.core.worker.task.TaskResult;

/**
 * ishalaru
 * 29.01.2021
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class PeriodicTaskMetrics {
    private static final String SOLOMON_LABEL_PERIODIC_TASK_TYPE = "periodic_task";
    private static final String SOLOMON_LABEL_TASK_RESULT = "result";
    private Map<PeriodicTaskType, PeriodicTaskMetrics.TaskMetrics> taskMetrics = new EnumMap<>(PeriodicTaskType.class);

    private final SolomonMetricRegistry solomonMetricRegistry;

    public void init() {
        SolomonTimerConfiguration solomonTimerConfiguration = makeSolomonTimeConfiguration();
        for (PeriodicTaskType type : PeriodicTaskType.values()) {
            SolomonKey baseKey = SolomonKey.create(SOLOMON_LABEL_PERIODIC_TASK_TYPE, type.name());
            Map<TaskResult, SolomonTimer> solomonCounters = new EnumMap<>(TaskResult.class);
            for (TaskResult result : TaskResult.values()) {
                solomonCounters.put(result, solomonMetricRegistry.createTimer(solomonTimerConfiguration, baseKey.withLabel(SOLOMON_LABEL_TASK_RESULT, result.name())));
            }
            taskMetrics.put(type, new TaskMetrics(solomonCounters));
        }
    }


    public SolomonTimerConfiguration makeSolomonTimeConfiguration() {
        SolomonTimerConfiguration solomonTimerConfiguration = new SolomonTimerConfiguration();
        solomonTimerConfiguration.setTimeUnit(TimeUnit.MILLISECONDS);
        solomonTimerConfiguration.setDurationIndicatorName("periodic_task_run");
        solomonTimerConfiguration.setBuckets(List.of(
                Duration.standardSeconds(10), Duration.standardSeconds(20), Duration.standardSeconds(100),
                Duration.standardMinutes(5), Duration.standardMinutes(15), Duration.standardMinutes(30),
                Duration.standardMinutes(60), Duration.standardHours(2), Duration.standardHours(4),
                Duration.standardHours(8), Duration.standardHours(12), Duration.standardHours(24)));
        solomonTimerConfiguration.setGroupBy(List.of("periodic_task,time_bucket", //Времена по таске, таски по времени
                "time_bucket",//Времена по всем таскам
                "periodic_task,result",//Результаты по таске, таски по результату
                "result",//езультаты по всем таскам
                ""//Общее количество запусков тасок
                ));
        solomonTimerConfiguration.setDurationGroupBy(List.of(""));

        return solomonTimerConfiguration;
    }

    public void taskFinish(PeriodicTaskType taskType, TaskResult taskResult, long duration) {
        taskMetrics.get(taskType).add(taskResult, duration);
    }


    @Value
    public class TaskMetrics {

        Map<TaskResult, SolomonTimer> solomonMetrics;


        public void add(TaskResult taskResult, long duration) {
            solomonMetrics.get(taskResult)
                    .update(Duration.millis(TimeUnit.NANOSECONDS.toMillis(duration)));
        }
    }
}
