# -*- coding: utf-8 -*-

from collections import OrderedDict
from datetime import datetime

from django.http import Http404

from common.models import Job
from common.util.clients import ClickhouseClient
from .base import ApiJob


class JobDist(ApiJob):
    """
    job results distributions
    """

    @staticmethod
    def get(request, job, distrib_type):
        """
        :param request: http request
        :param job: job object passed from request
        :param distrib_type:
        """
        tag = request.GET.get('case', '') or request.GET.get('tag', '')
        param_from = request.GET.get('from', '')
        param_to = request.GET.get('to', '')
        try:
            job = Job.objects.get(n=job.id)
            assert job.td
        except Job.DoesNotExist:
            raise Http404('Job not found')
        except AssertionError:
            raise Http404('Job is online')
        else:
            query_time = ''
            if param_from:
                query_time += "and time >= toDateTime('{}') ".format(datetime.strptime(param_from, "%Y%m%d%H%M%S"))
            if param_to:
                query_time += "and time <= toDateTime('{}') ".format(datetime.strptime(param_to, "%Y%m%d%H%M%S"))

            ch_client = ClickhouseClient()
            query_params = job.basic_query_params.copy()
            query_params['query_time'] = query_time
            query_params['tag'] = tag
            res = []
            if distrib_type in ['http', 'net', 'cases']:
                query = ''
                if distrib_type == 'http':
                    query = '''select code, toUInt32(sum(cnt)) 
                        from loaddb.proto_codes_buffer
                        where job_id={job}
                        and job_date=toDate({job_date})  
                        and tag='{tag}' 
                        {query_time} 
                        and cnt>0
                        group by code'''
                    headers = ['http', 'count', 'percent']
                elif distrib_type == 'net':
                    query = '''select code, toUInt32(sum(cnt)) 
                        from loaddb.net_codes_buffer
                        where job_id={job} 
                        and job_date=toDate({job_date}) 
                        and tag='{tag}' 
                        {query_time} 
                        and cnt>0
                        group by code'''
                    headers = ['net', 'count', 'percent']
                elif distrib_type == 'cases':
                    query = '''select tag, toUInt32(sum(resps)) 
                        from loaddb.rt_microsecond_details_buffer
                        where job_id={job} 
                        and job_date=toDate({job_date})  
                        and tag!='' 
                        {query_time} 
                        group by tag'''
                    headers = ['case', 'count', 'percent']
                arr = ch_client.select(query, query_params=query_params)
                overall = 0
                if not arr:
                    return []
                for a in arr:
                    overall = overall + a[1]
                if not overall:
                    return []
                for a in arr:
                    res.append(OrderedDict([
                        (headers[0], a[0]),
                        (headers[1], a[1]),
                        (headers[2], round(100.0 * a[1] / overall, 4)),
                    ]))
                return res
            elif distrib_type == 'times':
                query = '''select toFloat32(bin)/1000, toUInt32(sum(cnt))
                    from loaddb.rt_microsecond_histograms_buffer
                    where job_id={job} 
                    and job_date=toDate({job_date}) 
                    and tag='{tag}' 
                    {query_time} 
                    group by bin
                    order by bin'''
                arr = ch_client.select(query, query_params=query_params)
                if not arr:
                    return []
                arr = list(arr)
                arr[0] = list(arr[0])
                arr[0].append(arr[0][1])
                for i in range(1, len(arr)):
                    arr[i] = list(arr[i])
                    arr[i].append(arr[i][1] + arr[i - 1][2])
                overall = arr[-1][2]
                if not overall:
                    return []
                for a in arr:
                    res.append(OrderedDict([
                        ('ms', a[0]),
                        ('count', a[1]),
                        ('share', round(100.0 * a[1] / overall, 3)),
                        ('percentile', round(100.0 * a[2] / overall, 3)),
                    ]))
                return res

            elif distrib_type == 'percentiles':
                arg_percents = request.GET.get('percents',
                                               '50,75,80,85,90,95,98,99,100')
                percents = arg_percents.split(',')

                # quantilesExactWeighted accepts quantiles as '0.55, 0.998' and so on.
                query_params['percents'] = ','.join([str(float(p)/100) for p in percents])
                query = '''select 
                    quantilesExactWeighted({percents})(bin, cnt)
                    from loaddb.rt_microsecond_histograms_buffer
                    where job_id={job} 
                    and job_date=toDate({job_date}) 
                    and tag='{tag}' 
                    {query_time}
                '''
                arr = ch_client.select(query, query_params=query_params)
                if not arr:
                    return []
                data = dict(
                    list(zip(
                        percents,
                        # microseconds, so divide by 1000
                        [float(v)/1000 for v in arr[0][0]]
                    ))
                )
                for p in percents:
                    res.append(OrderedDict([
                        ('percentile', p),
                        ('ms', data[p]),
                    ]))
            return res
