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

import json
import logging

from django.http.response import HttpResponse
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django_yauth.decorators import yalogin_required

import settings
from common.util.clients import ClickhouseClient
from common.util.decorators import memoized_property
from common.views import get_common
from mobilepage.models import MobileComponent, MobileJob


@yalogin_required
def mobileregression(request, project, component_id=None):
    common_data = get_common(request)
    components = MobileComponent.objects.filter(tag=project)
    if not component_id and components.count():
        component_id = components[0].n
        return render_to_response('mobileregression.html',
                                  {'component_id': int(component_id),
                                   'common': common_data,
                                   'components': components,
                                   'project': project,
                                   },
                                  RequestContext(request)
                                  )
    elif str(component_id).isdigit() and int(component_id) in [c.n for c in components]:
        return render_to_response('mobileregression.html',
                                  {'component_id': int(component_id),
                                   'common': common_data,
                                   'components': components,
                                   'project': project,
                                   },
                                  RequestContext(request)
                                  )
    elif str(component_id).isdigit() and int(component_id) not in [c.n for c in components]:
        return render_to_response('error.html', {'common': common_data, 'error': 'no_mobilecomponent',
                                                 'project': project},
                                  RequestContext(request))
    elif not components.count():
        return render_to_response('error.html', {'common': common_data, 'error': 'no_mobilecomponents',
                                                 'project': project},
                                  RequestContext(request))


@yalogin_required
def choose_project(request):
    common_data = get_common(request)
    projects = sorted(set(c.tag for c in MobileComponent.objects.all()))
    return render_to_response('error.html',
                              {'common': common_data,
                               'error': 'no_mobile_regress_project',
                               'projects': projects
                               },
                              RequestContext(request))


def get_plot_data(request, component):
    if settings.RUNTIME_ENV:
        ch_url = 'http://lunapark-clickhouse.n.yandex-team.ru:80'
    else:
        ch_url = 'http{}://{}/api/dungeon'.format('s' if request.is_secure() else '', request.get_host())
    plot = MobileRegressionPlot(component, ch_url)
    return HttpResponse(json.dumps(plot.data()), content_type='application/json')


class MobileRegressionPlot(object):
    def __init__(self, component, ch_url):
        """
        
        :param component: str
        :param ch_url: str depends on environment and database location
        """
        self.component = component

        self.component_obj = MobileComponent.objects.get(n=self.component)
        self.ch_client = ClickhouseClient(url=ch_url, readonly=True)

    @memoized_property
    def job_objects(self):
        return [mj for mj in MobileJob.objects.filter(component=self.component_obj.n).order_by('n')]

    @memoized_property
    def old_jobs(self):
        return [mj for mj in self.job_objects if mj.version != '2']

    @memoized_property
    def new_jobs(self):
        return [mj for mj in self.job_objects if mj.version == '2']

    def data(self):
        sql_old = '''
            select test_id,
            round(avg(value), 3),
            round(quantile(0.50)(value), 3),
            round(quantile(0.75)(value), 3),
            round(quantile(0.8)(value), 3),
            round(quantile(0.85)(value), 3),
            round(quantile(0.9)(value), 3),
            round(quantile(0.95)(value), 3),
            round(quantile(0.98)(value), 3),
            round(quantile(0.99)(value), 3),
            round(max(value), 3)
            from volta.current
            where test_id in ({job_ids})
            group by test_id
        '''
        old_jobs_data = self.ch_client.select(sql_old, query_params={
            'job_ids': ','.join("'{}'".format(j.test_id) for j in self.old_jobs)
        })

        sql_new = '''
            select test_id,
            round(avg(value), 3),
            round(quantile(0.50)(value), 3),
            round(quantile(0.75)(value), 3),
            round(quantile(0.8)(value), 3),
            round(quantile(0.85)(value), 3),
            round(quantile(0.9)(value), 3),
            round(quantile(0.95)(value), 3),
            round(quantile(0.98)(value), 3),
            round(quantile(0.99)(value), 3),
            round(max(value), 3)
            from volta.currents
            where test_id in ({job_ids})
            group by test_id
        '''
        new_jobs_data = self.ch_client.select(sql_new, query_params={
            'job_ids': ','.join("'{}'".format(j.test_id) for j in self.new_jobs)
        })

        jobs_data = {j[0]: j[1:] for j in old_jobs_data}
        jobs_data.update({j[0]: j[1:] for j in new_jobs_data})
        assert jobs_data

        series = {
            'categories': [j.n for j in self.job_objects],
            'series': [
                          {
                              'name': 'avg',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[0] for j in self.job_objects],
                              'color': '#333',
                          },
                          {
                              'name': '50%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[1] for j in self.job_objects],
                              'color': self.color_mapping(50),
                              'type': 'area',
                          },
                          {
                              'name': '75%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[2] for j in self.job_objects],
                              'color': self.color_mapping(75),
                              'type': 'area',
                          },
                          {
                              'name': '80%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[3] for j in self.job_objects],
                              'color': self.color_mapping(80),
                              'type': 'area',
                          },
                          {
                              'name': '85%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[4] for j in self.job_objects],
                              'color': self.color_mapping(85),
                              'type': 'area',
                          },
                          {
                              'name': '90%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[5] for j in self.job_objects],
                              'color': self.color_mapping(90),
                              'type': 'area',
                          },
                          {
                              'name': '95%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[6] for j in self.job_objects],
                              'color': self.color_mapping(95),
                              'type': 'area',
                          },
                          {
                              'name': '98%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[7] for j in self.job_objects],
                              'color': self.color_mapping(98),
                              'type': 'area',
                          },
                          {
                              'name': '99%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[8] for j in self.job_objects],
                              'color': self.color_mapping(99),
                              'type': 'line',
                          },
                          {
                              'name': '100%',
                              'data': [jobs_data.get(j.test_id, [0] * 10)[9] for j in self.job_objects],
                              'color': self.color_mapping(100),
                              'type': 'line',
                          },
                      ][::-1],
            'names': {j.n: j.name for j in self.job_objects}
        }
        return series

    @staticmethod
    def color_mapping(quantile):
        color_map = {
            50: '#f85750',
            75: 'Coral',
            80: 'DarkOrange',
            85: 'Orange',
            90: 'gold',
            95: '#b8e13d',
            98: '#66af5f',
            99: '#7cb3f1',
            100: '#b2b8c8'
        }
        try:
            color = color_map[quantile]
            return color
        except KeyError:
            logging.warning('Unexpected quantile: {}'.format(quantile))
            return None
