# -*- coding: utf-8 -*-
"""
Created on Jul 26, 2013

@author: noob
"""

from common.models import Job, CustomUserReport
from common.util.clients import ClickhouseClient, CacheClient
from common.util.decorators import Memoize
from monitoring.models import Metric
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseServerError
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from hashlib import md5
from json import dumps
import logging


@login_required
def get_layout_template(request, job):
    job_obj = Job.objects.get(n=job)
    return render_to_response('panel.html', {'job': job_obj}, RequestContext(request))


@login_required
def get_layout(request, job):
    # user = request.user
    job_obj = Job.objects.get(n=job)
    # custom_reports = CustomUserReport.objects.filter(user=user.username, active=True)
    try:
        test_data_controls = get_test_data_controls(job_obj)
        monitoring_controls = get_monitoring_controls(job_obj, job_owner=(job_obj.user == request.user))

        logging.debug('LAYOUT TESTDATA %s', test_data_controls)

        layout = []

        if not job_obj.monitoring_only:
            layout.append({'name': 'test_data',
                           'title': 'Responses',
                           'controls': test_data_controls
                           })
        if job_obj.monitoring_exists:
            layout.append({'name': 'monitoring',
                           'title': 'Monitoring',
                           'controls': monitoring_controls
                           })
        # TODO:    if custom_reports:
        #             for cur in custom_reports:
        #                 layout.append({'name': 'custom__' + str(cur.n),
        #                        'title': cur.name.split(':')[1].strip() or 'custom:%s' % cur.n,
        #                        'controls': get_custom_controls(job_obj, cur, job_owner=(job_obj.user==request.user))
        #                        })
        return HttpResponse(dumps(layout), content_type='application/json')
    except ObjectDoesNotExist:
        logging.warning('No such Job: %s', job)
        return HttpResponseBadRequest
    except:
        logging.exception('Could not get layout for job %s due to:', job)
        return HttpResponseServerError


def get_test_data_controls(job_obj):
    """
    returns list of dicts with controls for monitoring tab layout
    slider, targers, metric_groups
    :param job_obj: Job OBJECT
    """
    try:
        if job_obj.multitag:
            delimiter = '|'
            tags = []
            for case in job_obj.cases:
                tags.extend(case.split(delimiter))
            cases = sorted([tag for tag in set(tags)])
        else:
            cases = job_obj.cases
        test_data_layout = [
            {'name': 'plot_groups',
             'type': 'radio',
             'default': 'main',
             'values': (('main', u'Overview'),
                        ('extended', u'Extended analysis'),
                        ('additional', u'Distributions'),
                        # TODO:                                           ('tables', u'Tables'),
                        )
             },
            {'name': 'tags',
             'type': 'radio',
             'default': '',
             'values': zip([''] + [md5(c.encode('utf-8')).hexdigest() for c in cases], ['Overall'] + cases)
             },
        ]
        logging.info('Got test_data controls for job %s', job_obj.n)
        return test_data_layout
    except:
        logging.exception('Could not get test_data_controls for job %s due to:', job_obj.n)
        return None


def get_monitoring_controls(job_obj, job_owner=False):
    """
    returns list of dicts with controls for monitoring tab layout
    slider, targers, metric_groups
    :param job_obj: Job OBJECT
    :param job_owner: boolean
    """
    try:
        monitoring_controls_processor = MonitoringControlsProcessor(job_obj, job_owner=job_owner)
        if not job_obj.monitoring_exists:
            logging.info('No monitoring for job %s', job_obj.n)
            return None
        else:
            logging.error('Mon EXISTS %s', job_obj.monitoring_exists)
            monitoring_controls = [
                {'name': 'machines',
                 'type': 'radio',
                 'default': monitoring_controls_processor.default_target,
                 'values': monitoring_controls_processor.targets
                 },
                {'name': 'metrics',
                 'type': 'radio',
                 'default': monitoring_controls_processor.default_metrics_group,
                 'values': zip([''] + monitoring_controls_processor.metrics_groups,
                               [u'All metrics'] + monitoring_controls_processor.metrics_groups)
                 }]
            logging.info('Got monitoring_controls for job %s', job_obj.n)
            return monitoring_controls
    except:
        logging.exception('Could not get monitoring_controls for job %s due to:', job_obj.n)
        return None


def get_custom_controls(job_obj, cur, job_owner=False):
    """

    :param job_obj: Job OBJECT
    :param cur: CustomUserReport OBJECT
    :param job_owner: boolean
    """
    if job_obj.multitag:
        delimiter = '|'
        tags = []
        for case in job_obj.cases:
            tags.extend(case.split(delimiter))
        cases = sorted([tag for tag in set(tags)])
    else:
        cases = job_obj.cases
    custom_report_layout = [
        {'name': 'plot_groups',
         'type': 'radio',
         'default': 'main',
         'values': (('main', cur.name.split(':')[1].strip() or 'custom:%s' % cur.n),)
         },
        {'name': 'tags',
         'type': 'radio',
         'default': '',
         'values': zip([''] + [md5(c.encode('utf-8')).hexdigest() for c in cases], ['Overall'] + cases),
         },
    ]
    if job_obj.monitoring_exists and [p for p in cur.plots if p.startswith('monitoring_')]:
        monitoring_controls_processor = MonitoringControlsProcessor(job_obj, job_owner=job_owner)
        custom_report_layout.append({
            'name': 'machines',
            'type': 'radio',
            'default': monitoring_controls_processor.default_target,
            'values': monitoring_controls_processor.targets,
        })
    return custom_report_layout


@login_required
def get_single_report_controls(request, job):
    """

    :param request: HTTP Request
    :param job: Job NUMBER
    """
    try:
        job_obj = Job.objects.get(n=job)
        cur_n = request.GET.get('cur', '0')
        cur = CustomUserReport.objects.get(n=cur_n)
        controls = {'name': 'custom__' + str(cur.n),
                    'title': cur.name.split(':')[1].strip() or 'custom:%s' % cur.n,
                    'controls': get_custom_controls(job_obj, cur)
                    }
        return HttpResponse(dumps(controls), content_type='application/json')
    except:
        logging.exception('')
        return HttpResponseBadRequest()


class MonitoringControlsProcessor(object):
    def __init__(self, job_obj, job_owner=False):
        """

        :param job_obj: Job OBJECT
        """
        self.job_obj = job_obj
        self.job_owner = job_owner
        self.ch_client = ClickhouseClient()
        self.cache = CacheClient()

    @property
    @Memoize
    def targets(self):
        """
        returns tuple of tuples
        """
        try:
            targets = tuple(
                [(target.n, target.host if self.job_owner else 'mysterious host %s' % target.n, target.dsc) for target
                 in self.job_obj.targets])
            # TODO:        if len(targets) > 1:  # adding all targets tab
            #                 targets = tuple(list(targets) + [(-1, u'All targets', u'All targets')])
            logging.error('Got targets for job %s: %s', self.job_obj.n, targets)
            return targets
        except:
            logging.exception('Could not get targets for job %s. Taking job srv as target', self.job_obj.n)
            targets = ((self.job_obj.srv.n, self.job_obj.srv.host, self.job_obj.srv.dsc),)
            return targets

    @property
    def default_target(self):
        """
        returns target's number
        """
        if self.job_obj.srv in self.job_obj.targets:
            try:
                default_target = self.job_obj.srv.n
                logging.error("Taking job's %s srv as a default_target: %s", self.job_obj.n, default_target)
                return default_target
            except:
                logging.exception('Could not get default_target for job %s due to:', self.job_obj.n)
                return None
        else:
            default_target = self.targets[0][0]
            logging.error('Picked default_target for job %s: %s', self.job_obj.n, default_target)
            return default_target

    @property
    @Memoize
    def metrics_groups(self):
        """
        returns list of unique metric groups for all targets
        """
        try:
            metrics = []
            for target in self.targets:
                metrics += set(self.get_target_metrics(target).keys())
            logging.info('Got metrics_groups for job %s', self.job_obj.n)
            metrics_groups = [metric.split(':')[0].split('_')[0] for metric in metrics]
            return sorted(set(metrics_groups))  # TODO: [u'Aggregates'] + sorted(set(metrics_groups))
        except:
            logging.exception('Could not get metrics_groups for job %s due to:', self.job_obj.n)
            return None

    @property
    def default_metrics_group(self):
        try:
            default_metrics_group = self.metrics_groups[0]
            logging.error('Default monitoring metrics group for job %s is %s', self.job_obj.n, default_metrics_group)
            return default_metrics_group
        except:
            logging.exception('Could not get default_metrics_group for job %s due to:', self.job_obj.n)
            return None

    def get_target_metrics(self, target):
        """
        cache for all monitoring plots for this job
        returns dict where metric codes are keys, and ids are values
        :target: tuple (Server.n, Server.host)
        """
        try:
            sql = '''
                select distinct metric_name
                from loaddb.monitoring_verbose_data_buffer
                where job_id=%(job)s 
                and job_date=toDate(%(job_date)s)
                and target_host='%(target)s'
            '''
            query_params = self.job_obj.basic_query_params.copy()
            query_params['target'] = target[1]
            metric_ids = self.ch_client.select(sql, query_params=query_params)

            if metric_ids:
                metrics = {}
                for i in metric_ids:
                    metric_obj = Metric.objects.get_or_create(code=i[0])[0]
                    metrics[metric_obj.code] = metric_obj.id
            else:
                metrics = {}
            logging.debug('Got monitoring metrics for job %s, machine %s: %s', self.job_obj.n, target, metrics)
            return metrics
        except:
            logging.exception('Could not get monitoring metrics for job %s due to:', self.job_obj.n)
            return {}
