# -*- coding: utf-8 -*-
"""
Created on Apr 29, 2013

@author: noob
"""

from common.models import Job, Project, UISettings
from common.util.clients import ClickhouseClient, CacheClient
from common.views import get_common
from common.util.decorators import approve_required
from takeout.tvm_ticketer import Ticketer
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import render_to_response, redirect, render
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout as auth_logout, login
from django.conf import settings
from django.views.decorators.csrf import csrf_protect
from social_core.backends.oauth import BaseOAuth1, BaseOAuth2
from social_core.backends.utils import load_backends
from social_django.utils import psa

import json
import logging

from functools import wraps


TICKETER = Ticketer()


def render_to(tpl):
    def decorator(func):
        @wraps(func)
        def wrapper(request, *args, **kwargs):
            out = func(request, *args, **kwargs)
            if isinstance(out, dict):
                out = render_to_response(tpl, out, RequestContext(request))
            return out

        return wrapper

    return decorator


@csrf_protect
def logout(request):
    """Logs out user"""
    auth_logout(request)
    return redirect('/')


def context(**extra):
    if not TICKETER.check_ticket(settings.GOZORA_TVM):
        settings.GOZORA_TVM = TICKETER.get_ticket('gozora')
        settings.PROXIES = {
            'http': 'http://{}:{}@go.zora.yandex.net:1080/'.format(settings.GOZORA_USER, settings.GOZORA_TVM),
            'https': 'http://{}:{}@go.zora.yandex.net:1080/'.format(settings.GOZORA_USER, settings.GOZORA_TVM),
        }
    return dict({
        'common': {'CSP_SCRIPT_NONCE': settings.CSP_SCRIPT_NONCE},
        'client_id': settings.SOCIAL_AUTH_YANDEX_OAUTH2_KEY,
        #         'yandex_scope': ' '.join(['https://oauth.yandex.com/authorize', 'https://oauth.yandex.com/token']),
        'available_backends': load_backends(settings.AUTHENTICATION_BACKENDS)
    }, **extra)


@render_to('home.html')
def home(request):
    """Home view, displays login mechanism"""
    if request.user.is_authenticated():
        return redirect('/')
    return context()


@login_required
@render_to('home.html')
def done(request):
    """Login complete view, displays user data"""
    if request.user.is_authenticated():
        return redirect('/mainpage/guide')
    return context()


@render_to('home.html')
def validation_sent(request):
    return context(
        validation_sent=True,
        email=request.session.get('email_validation_address')
    )


@render_to('home.html')
def require_email(request):
    backend = request.session['partial_pipeline']['backend']
    return context(email_required=False, backend=backend)


@psa('social:complete')
def ajax_auth(request, backend):
    if isinstance(request.backend, BaseOAuth1):
        token = {
            'oauth_token': request.REQUEST.get('access_token'),
            'oauth_token_secret': request.REQUEST.get('access_token_secret'),
        }
    elif isinstance(request.backend, BaseOAuth2):
        token = request.REQUEST.get('access_token')
    else:
        raise HttpResponseBadRequest('Wrong backend type')
    user = request.backend.do_auth(token, ajax=True)
    login(request, user)
    data = {'id': user.id, 'username': user.username}
    return HttpResponse(json.dumps(data), mimetype='application/json')


@login_required
@approve_required
def mainpage(request):
    """

    :param request: HTTP request
    """
    user = request.user
    common_data = get_common(request, user.id)
    projects = Project.objects.filter(owner=user.username)

    ui__show_user_jobs = UISettings.objects.filter(user=user, param='show_user_jobs')
    if ui__show_user_jobs:
        ui__show_user_jobs = ui__show_user_jobs[0].onoff
    else:
        ui__show_user_jobs = False

    for_user = request.GET.get('user', '')

    if common_data['approved']:
        resp = render(request, 'mainpage.html', {'common': common_data,
                                                 'user': user,
                                                 'projects': projects,
                                                 'ui__show_user_jobs': ui__show_user_jobs,
                                                 'for_user': for_user,
                                                 }, RequestContext(request))

    else:
        resp = redirect('/mainpage/guide/')
    return resp


@login_required
def mainpage_guide(request):
    """

    :param request: HTTP request
    """
    user = request.user
    common_data = get_common(request, user.id)

    try:
        cache = CacheClient()
        ui__show_user_jobs = bool(cache.get('ui__show_user_jobs__%s' % user.id))
    except Exception as exc:
        logging.error("CAAS ERROR %s", repr(exc))
        ui__show_user_jobs = False
    resp = render_to_response('mainpage_guide.html', {'common': common_data,
                                                      'user': user,
                                                      'ui__show_user_jobs': ui__show_user_jobs,
                                                      }, RequestContext(request))

    return resp


@login_required
def generate_preview(request):
    """

    :param request: HTTP Request
    """

    try:
        job_n = request.GET.get('job')
        assert job_n
        job_obj = Job.check_job(Job.objects.get(n=job_n))
    except Job.Deleted:
        return HttpResponse(json.dumps([{'success': 0, 'msg': 'Job had been deleted'}]), content_type='application/json')
    except (AssertionError, Job.DoesNotExist):
        return HttpResponseBadRequest('no such job %s' % job_n)

    cache = CacheClient()
    cache_key = 'job_%s_preview' % job_obj.n
    try:
        assert job_obj.td
        data = cache.get(cache_key)
        if data:
            logging.info('Found %s in cache', cache_key)
        else:
            logging.info('No %s in cache', cache_key)
            raise KeyError()
    except:
        try:
            # Тип схемы нагрузки
            sql = '''
                select any(job_id)
                from loaddb.rt_microsecond_details_buffer
                where job_id=%(job)s
                and job_date=toDate(%(job_date)s) 
                and reqps!=0
            '''
            ch_client = ClickhouseClient()
            nonzero_reqps = ch_client.select(sql, query_params=job_obj.basic_query_params)[0][0]
            if nonzero_reqps:
                scheme_type = 'reqps'
                scheme_color = '#800000'  # BF0129
            else:
                scheme_type = 'threads'
                scheme_color = '#ff00ff'
            try:
                trail_count = ch_client.select('''
                    select toUInt32(count()) 
                    from loaddb.rt_microsecond_details_buffer
                    where job_id=%(job)s 
                    and job_date=toDate(%(job_date)s) 
                    and tag = ''
                    ''', query_params=job_obj.basic_query_params)[0][0]
            except IndexError:
                logging.warning('No data for job %s preview', job_obj.n)
                return HttpResponse(json.dumps([]), content_type="application/json")
            # чем больше знаменатель, тем больше точек на графике (100 соответствует 0-199 точек)
            compress_ratio = trail_count / 100 or 1
            # Довольно грубая выборка. 
            # Без усреднения и взвешивания. 
            # Даже не гарантирует, что будет последний трейл. 
            # Но для превью сойдет.

            sql = '''
                select mq50, mq75, mq80, mq85, mq90, mq95, mq98, mq99, mq100, toUInt32(scheme) from
                (
                select any(%(scheme)s) as scheme,
                intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
                from loaddb.rt_microsecond_details_buffer
                where job_id=%(job)s
                and job_date=toDate(%(job_date)s) 
                and tag = ''
                group by t
                order by t
                ) all left join
                (
                select 
                round(max(q50), 3) as mq50,
                round(max(q75), 3) as mq75,
                round(max(q80), 3) as mq80,
                round(max(q85), 3) as mq85,
                round(max(q90), 3) as mq90,
                round(max(q95), 3) as mq95,
                round(max(q98), 3) as mq98,
                round(max(q99), 3) as mq99,
                round(max(q100), 3) as mq100,
                intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
                from loaddb.rt_quantiles_buffer
                where job_id=%(job)s
                and job_date=toDate(%(job_date)s) 
                and tag=''
                group by t
                order by t
                )
                using t'''
            query_params = job_obj.basic_query_params.copy()
            query_params.update({
                'compress_ratio': compress_ratio,
                'scheme': scheme_type,
            })
            trail_data = ch_client.select(sql, query_params=query_params)
            assert trail_data
            data = [
                       {'data': [v[-1] for v in trail_data] if nonzero_reqps else [v[-1] if v[-1] else None for v in
                                                                                   trail_data],
                        'color': scheme_color,
                        'marker': {'enabled': False},
                        'lineWidth': 2,
                        'states': {'hover': {'enabled': False}},
                        'yAxis': 1,
                        },
                       {'data': [v[0] for v in trail_data],
                        'color': '#f85750',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[1] for v in trail_data],
                        'color': 'Coral',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[2] for v in trail_data],
                        'color': 'DarkOrange',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[3] for v in trail_data],
                        'color': 'Orange',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[4] for v in trail_data],
                        'color': 'gold',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[5] for v in trail_data],
                        'color': '#b8e13d',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[6] for v in trail_data],
                        'color': '#66af5f',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[7] for v in trail_data],
                        'color': '#7cb3f1',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                       {'data': [v[8] for v in trail_data],
                        'color': '#b2b8c8',
                        'marker': {'enabled': False},
                        'lineWidth': 1,
                        'type': 'spline',
                        'states': {'hover': {'enabled': False}},
                        },
                   ][::-1]
            if job_obj.td:
                cache.set(cache_key, data)
        except AssertionError:
            data = []
        except:
            logging.exception('')
            data = []
    return HttpResponse(json.dumps(data), content_type='application/json')
