# -*- coding: utf-8 -*-
"""
Created on Feb 28, 2014

@author: noob
"""
from common.util.meta import escape_string
from common.util.decorators import memoized_property
from .plots_base import DistComparePlot
from collections import OrderedDict
from itertools import chain
import logging


class QuantilesVsTimes(DistComparePlot):
    title = 'Распределение времен ответов (процентиль)'
    yaxis_label = ' %'
    xaxis_label = 'ms'

    @property
    def overrides(self):
        """
        dict
        overriding default highcharts config
        """
        overrides = super(QuantilesVsTimes, self).overrides
        if 'yAxis' not in list(overrides.keys()):
            overrides['yAxis'] = {}
        overrides['yAxis']['showFirstLabel'] = False
        overrides['yAxis']['showLastLabel'] = False
        if 'plotOptions' not in list(overrides.keys()):
            overrides['plotOptions'] = {}
        overrides['plotOptions']['spline'] = {'lineWidth': 3}
        return overrides

    @memoized_property
    def xaxis_points(self):
        """
        returns list
        """
        try:
            xaxis_points = sorted(set(chain.from_iterable(list(data.keys()) for data in list(self.data_values_dict.values()))))
            return xaxis_points
        except:
            logging.exception('Could not get xaxis_points for {} for jobs {} due to'
                              .format(self.__class__.__name__, [job.n for job in self.job_objects]))
            return None

    @staticmethod
    def count_quantiles(data):
        """
        returns list
        :param data: list of count
        """
        data = [value if value else 0 for value in data]
        summa = sum(data) or 1
        quantiles_data = [round(float(value) * 100 / summa, 3) for value in
                          [sum(data[0:i]) for i in range(1, len(data) + 1)]]
        return quantiles_data

    def fetch_data(self, job_obj):
        """
        returns tuple of tuples of times and resp count
        """
        try:
            query_params = job_obj.basic_query_params.copy()
            query_params.update({
                'start': self.intervals[job_obj.n]['start'],
                'end': self.intervals[job_obj.n]['end'],
            })
            sql = '''select bin/1000, toUInt32(sum(cnt))
                from loaddb.rt_microsecond_histograms_buffer
                where job_id={job} 
                and job_date=toDate({job_date}) 
                '''
            if job_obj.multitag and self.case:
                tag = self.case
                cases_with_tag = ["'{}'".format(escape_string(str(case))) for case in job_obj.cases if
                                  tag in case.split("|")]
                sql += 'and tag in ({cases_with_tag}) '
                query_params['cases_with_tag'] = ','.join(cases_with_tag)
            else:
                sql += '''and tag='{tag}'  '''
                query_params['tag'] = self.case
            sql += '''and time >= toDateTime({start})
                and time <= toDateTime({end}) 
                group by bin
                order by bin desc;'''
            data = self.ch_client.select(sql, query_params=query_params)
            return data
        except:
            logging.exception('could not retrieve data_values for {} for job {} due to:'
                              .format(self.__class__.__name__, job_obj.n))
            return (()),

    @memoized_property
    def data_values_dict(self):
        try:
            data_values_dict = {}
            for job_obj in self.job_objects:
                data_values_dict[job_obj.n] = dict(self.fetch_data(job_obj))
            sorted_data_values = OrderedDict()
            for job_obj in self.job_objects:
                sorted_data_values[job_obj.n] = sorted(list(data_values_dict[job_obj.n].items()), key=lambda x: x[0])
                sorted_data_values[job_obj.n] = OrderedDict(sorted_data_values[job_obj.n])
            return sorted_data_values
        except:
            logging.exception('could not make data_values_dict for {} for jobs {} due to:'
                              .format(self.__class__.__name__, [job.n for job in self.job_objects]))
            return {}

    @property
    def yaxis(self):
        return {
                   'plotLines': [{
                       'color': '#808080',
                       'value': 0,
                       'width': 1
                   }],
                   'showFirstLabel': False,
                   'showLastLabel': False,
                   'labels': {
                       'align': 'left',
                       'x': 10,
                       'y': -4,
                   },
                   'title': {
                       'text': '',
                   },
                   #                 'min': -5,
                   #                 'max': 105,
                   'allowDecimals': False,
                   'type': 'spline' if self.ticks > 1 else 'column',
                   'label': self.yaxis_label,
               },

    @property
    def series_data(self):
        series_data = []
        for job_obj in self.job_objects:
            serie = {
                'marker': {
                    'symbol': 'circle'
                },
                'name': str(job_obj.n) + ' ' + str(job_obj.name),
                'color': self.color_mapping(self.job_objects.index(job_obj)),
                'type': 'spline',
                'label': self.yaxis_label,
            }
            try:
                serie['data'] = []
                for point in self.xaxis_points:
                    try:
                        serie['data'].append(self.data_values_dict[job_obj.n][point])
                    except KeyError:
                        serie['data'].append(0)
                serie['data'] = self.count_quantiles(serie['data'])
            except KeyError:
                logging.exception('KEYERROR')
                serie['data'] = [0] * self.jobs.count()
            series_data.append(serie)
        return series_data


class TimesDistCountPlot(QuantilesVsTimes):
    title = 'Распределение времен ответов (количество)'
    yaxis_label = ''

    @property
    def overrides(self):
        """
        dict
        overriding default highcharts config
        """
        overrides = super(TimesDistCountPlot, self).overrides
        if 'plotOptions' not in list(overrides.keys()):
            overrides['plotOptions'] = {}
        overrides['plotOptions'] = {'series': {'animation': False}}
        return overrides

    @property
    def yaxis(self):
        return {'plotLines': [{'color': '#808080',
                               'value': 0,
                               'width': 1}],
                'showFirstLabel': False,
                'showLastLabel': False,
                'labels': {'align': 'left',
                           'x': 10,
                           'y': -4, },
                'title': {'text': ''},
                'allowDecimals': False,
                'type': 'column',
                'label': self.yaxis_label,
                },

    @property
    def series_data(self):
        series_data = []
        for job_obj in self.job_objects:
            serie = {'name': str(job_obj.n) + ' ' + str(job_obj.name),
                     'type': 'column',
                     'pointPadding': -0.3,
                     'color': self.color_mapping(self.job_objects.index(job_obj)),
                     'stack': 0,
                     'label': self.yaxis_label,
                     }
            try:
                serie['data'] = []
                for point in self.xaxis_points:
                    try:
                        serie['data'].append(self.data_values_dict[job_obj.n][point])
                    except KeyError:
                        serie['data'].append(0)
                serie['data'] = [value if value else 0 for value in serie['data']]
            except KeyError:
                logging.exception('KEYERROR')
                serie['data'] = [0] * self.jobs.count()
            series_data.append(serie)
        return series_data


class TimesDistPercentPlot(TimesDistCountPlot):
    title = 'Распределение времен ответов (доля)'
    yaxis_label = ' %'

    @property
    def series_data(self):
        series_data = []
        for job_obj in self.job_objects:
            serie = {'name': str(job_obj.n) + ' ' + str(job_obj.name),
                     'type': 'column',
                     'pointPadding': -0.3,
                     'color': self.color_mapping(self.job_objects.index(job_obj)),
                     'stack': 0,
                     'label': self.yaxis_label,
                     }
            try:
                serie['data'] = []
                for point in self.xaxis_points:
                    try:
                        serie['data'].append(self.data_values_dict[job_obj.n][point])
                    except KeyError:
                        serie['data'].append(0)
            except KeyError:
                logging.exception('KEYERROR')
                serie['data'] = [0] * self.jobs.count()
            serie['data'] = self.count_percentage(serie['data'])
            series_data.append(serie)
        return series_data
