# coding: utf-8


import abc

from django.http import HttpResponse, HttpResponseBadRequest
from django.views.generic import View
from metrics_framework.models import MetricPoint

from idm.monitorings.answer import MonitoringAnswer
from idm.monitorings.metric import CachedMetric


class BaseMonitoringView(View, metaclass=abc.ABCMeta):
    ERROR_DELIMITER = ' | '

    @abc.abstractmethod
    def monitoring(self):
        """ Реализация мониторинга. В случае ошибки должна вернуть ошибку или список ошибок.
        В случае успеха None или пустой список
        """
        return []

    def get(self, request, *args, **kwargs):
        # Сохраняем request для мониторинга с параметрами
        self.request = request

        status_code = HttpResponse().status_code
        response_data = 'ok'

        errors = self.monitoring()

        if errors:
            status_code = HttpResponseBadRequest().status_code
            if isinstance(errors, MonitoringAnswer):
                status_code = errors.status_code
                errors = errors.messages

            if isinstance(errors, str):
                errors = [errors]
            response_data = self.ERROR_DELIMITER.join(errors)

        return HttpResponse(
            response_data,
            status=status_code,
        )


class BaseMetricMonitoringView(BaseMonitoringView):
    @property
    @abc.abstractmethod
    def metric_slug(self):
        pass

    @abc.abstractmethod
    def is_bad_value(self, value):
        pass

    def monitoring(self):
        last_point = MetricPoint.objects.filter(metric__slug=self.metric_slug).order_by('-created_at').first()
        if not last_point:
            return ['No data']
        elif last_point.is_outdated():
            return ['Last updated at %s' % last_point.created_at]

        bad_values = []
        for value in last_point.values.all():
            if self.is_bad_value(value.value):
                bad_values.append(str(value))
        return bad_values


class BaseCachedMonitoring(BaseMonitoringView):
    cached_metric: CachedMetric

    def __init_subclass__(cls, **kwargs):
        assert hasattr(cls, 'cached_metric') and isinstance(cls.cached_metric, CachedMetric)

    @abc.abstractmethod
    def get_errors_from_cached_value(self, cached_value):
        pass

    def monitoring(self):
        cached_value = self.cached_metric.get()
        if cached_value is None:
            return 'Cache is empty!'

        return self.get_errors_from_cached_value(cached_value)
