# -*- coding: utf-8 -*-
"""
Created on Jul 1, 2016

@author: noob
"""

import logging
from hashlib import md5
from json import dumps

from django.core.exceptions import ObjectDoesNotExist
from django.db import connections
from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponse, HttpRequest, \
    HttpResponseServerError
from django.shortcuts import render_to_response, render
from django.template import RequestContext
from django_yauth.decorators import yalogin_required
from django_yauth.user import YandexUser

from api.views.jobclose import JobClose
from common.models import Job, DeletedJob, LoadScheme, Task
from firestarter.models import JobTank
from common.util.clients import ClickhouseClient, CacheClient
from common.views import get_common
from monitoring.models import JobMetricTarget
from offlinepage.views import Metainfo
from .layout import MonitoringControlsProcessor


@yalogin_required
def onlinepage(request, job):
    """

    :param request: HTTP request
    :param job: Job NUMBER
    """
    user = request.yauser
    common_data = get_common(request)
    try:
        job_obj = Job.objects.get(n=job)
    except ObjectDoesNotExist:
        return render_to_response('error.html', {'common': common_data, 'error': 'no_job'},
                                  RequestContext(request))
    if not job_obj.is_online:  # offline
        return HttpResponseRedirect('/{}'.format(job_obj.n))  # redirect to offline page

    memcached = CacheClient()
    in_memcache = False
    try:
        data_is_present = memcached.get('job_{}_dataispresent'.format(job_obj.n))
        in_memcache = bool(data_is_present)
        if not data_is_present:
            ch_client = ClickhouseClient()
            data_is_present = bool(ch_client.select('''
                select
                any(job_id) as j
                from loaddb.rt_microsecond_details_buffer
                where job_id={job}
                and job_date=toDate({job_date})
                union all
                select
                any(job_id) as j
                from loaddb.monitoring_verbose_data_buffer
                where job_id={job}
                and job_date=toDate({job_date})
                ''', query_params=job_obj.basic_query_params))
    except:
        logging.exception('')
        data_is_present = False

    if not data_is_present and job_obj.status == 'queued':
        job_tank = JobTank.objects.filter(job_id=job_obj.n)
        return render_to_response('error.html',
                                  {'common': common_data, 'job_id': job_obj.n, 'error': 'job_is_queued',
                                   'use_tank': ', '.join([jt.tank.host for jt in job_tank])},
                                  RequestContext(request))
    elif not data_is_present:
        return render_to_response('error.html',
                                  {'common': common_data, 'job_id': job_obj.n, 'error': 'no_data_in_trail'},
                                  RequestContext(request))
    elif data_is_present and not in_memcache:
        memcached.set('job_{}_dataispresent'.format(job_obj.n), True)
    try:
        loadscheme = job_obj.loadscheme_set.all()
        scheme = []
        if loadscheme:
            loadscheme = loadscheme.order_by('load_from')
            load_from = loadscheme[0].load_from
            load_to = loadscheme[loadscheme.count() - 1].load_to
            prev_dsc = ''
            for ls in loadscheme:
                if not prev_dsc or prev_dsc != ls.dsc:
                    scheme.append(ls.dsc)
                prev_dsc = ls.dsc
        else:
            load_from = 0
            load_to = 0
        scheme = ', '.join(scheme) if scheme else ''
        metainfo = Metainfo(job_obj)

        task = Task.objects.filter(key=job_obj.task)[0]
        navfire_a = Job.objects.filter(task=job_obj.task).order_by('-n')[:50]

        return render_to_response('onlinepage.html', {'user': user,
                                                      'common': common_data,
                                                      'job': job_obj,
                                                      'task': task,
                                                      'navfire': navfire_a,
                                                      'schema': scheme,
                                                      'load_from': load_from,
                                                      'load_to': load_to,
                                                      'net_errors': metainfo.net_errors,
                                                      'http_codes': metainfo.http_codes,
                                                      'user_agent': metainfo.user_agent,
                                                      'multitag': job_obj.multitag,
                                                      'has_monitoring': job_obj.monitoring_exists,
                                                      'configinitial': bool(job_obj.configinitial),
                                                      'pagename': 'onlinepage',
                                                      }, RequestContext(request))
    except:
        logging.exception('Could not render onlinepage for job {} due to:'.format(job))
        return render_to_response('error.html', {'common': common_data, 'error': 'no_job'},
                                  RequestContext(request))


@yalogin_required
def progress_bar_info(request):
    try:
        job = request.GET.get('job')
        assert job
        job_obj = Job.objects.get(n=job)
        return HttpResponse(dumps({'start': job_obj.data_started_unix,
                                   'end': job_obj.data_started_unix + job_obj.estimated_duration,
                                   }))
    except (ObjectDoesNotExist, AssertionError):
        return HttpResponseBadRequest('invalid job specified')
    except Exception:
        logging.exception('')
        return HttpResponseServerError('')


@yalogin_required
def refresh_meta_info(request):
    try:
        job = request.GET.get('job')
        assert job
        job_obj = Job.objects.get(n=job)
        metainfo = Metainfo(job_obj)
        return HttpResponse(dumps({'online': job_obj.is_online,
                                   'net_errors': metainfo.net_errors,
                                   'http_codes': metainfo.http_codes,
                                   }))
    except (ObjectDoesNotExist, AssertionError):
        return HttpResponseBadRequest('invalid job specified')
    except Exception:
        logging.exception('')
        return HttpResponseServerError('')


@yalogin_required
def refresh_tags(request):
    try:
        job = request.GET.get('job')
        assert job
        job_obj = Job.objects.get(n=job)
        return HttpResponse(
            dumps([('', 'Overall')] + [(md5(tag.encode('utf-8')).hexdigest(), tag) for tag in job_obj.tags]),
            content_type='application/json')
    except (ObjectDoesNotExist, AssertionError):
        return HttpResponseBadRequest('invalid job specified')
    except Exception:
        logging.exception('')
        return HttpResponseServerError('')


@yalogin_required
def refresh_monitoring_controls(request):
    try:
        job = request.GET.get('job')
        assert job
        job_obj = Job.objects.get(n=job)
        controls = MonitoringControlsProcessor(job_obj)
        return HttpResponse(dumps({'targets': controls.targets,
                                   'metrics': controls.metrics_groups}), content_type='application/json')
    except (ObjectDoesNotExist, AssertionError):
        return HttpResponseBadRequest('invalid job specified')
    except Exception:
        logging.exception('')
        return HttpResponseServerError('')


@yalogin_required
def render_custom_report_form(request):
    try:
        job = request.GET.get('job')
        assert job
        job_obj = Job.objects.get(n=job)
        custom_metrics = [jmt.metric
                          for jmt in JobMetricTarget(job_obj.n, bypass_cache=True).objects
                          if jmt.metric.startswith('custom:')]
        custom_metrics_single = set([metric.split(":")[1]
                                     for metric in custom_metrics
                                     if [m.split(":")[1].split('_')[0] for m in custom_metrics].count(
                metric.split(":")[1].split('_')[0]) == 1])
        custom_metrics_groups = set([metric.split(":")[1].split('_')[0]
                                     for metric in custom_metrics
                                     if [m.split(":")[1].split('_')[0] for m in custom_metrics].count(
                metric.split(":")[1].split('_')[0]) > 1])

        return render(request, 'custom_report_form.html', {
            'job': job_obj.n,
            'custom_metrics_single': custom_metrics_single,
            'custom_metrics_groups': custom_metrics_groups,
            'targets': job_obj.targets,
        })
    except (ObjectDoesNotExist, AssertionError):
        return HttpResponseBadRequest('invalid job specified')


@yalogin_required
def addtofav(request):
    job_n = request.POST.get('job_id', 0)
    try:
        job_obj = Job.objects.get(n=job_n)
    except (ObjectDoesNotExist, ValueError):
        return HttpResponseBadRequest('Invalid job')
    job_obj.flag = 0 if job_obj.flag else 1
    job_obj.save()
    return HttpResponse(dumps({'status': 1, 'error': ''}), content_type='application/json')


@yalogin_required
def deletejob(request):
    job_n = request.POST.get('job_id', 0)
    job = Job.objects.filter(n=job_n)
    if not job:
        return HttpResponse(dumps({'status': 0, 'error': 'There is no such job!'}), content_type='application/json')
    _delete_job(job[0], user=request.yauser.login)
    return HttpResponse(dumps({'status': 1, 'error': ''}), content_type='application/json')


def _delete_job(job, user='overload'):
    """

    :param job: Job OBJECT
    """
    try:
        if not job.td:  # close online job before deleting;
            request = HttpRequest()
            request.method = 'get'
            request.yauser = YandexUser.objects.get(login=user)
            riper = JobClose()
            riper.get(request, job)

        d = DeletedJob(n=job.n,
                       task=job.task,
                       fd=job.fd,
                       td=job.td,
                       user=job.user,
                       name=job.name,
                       dsc=job.dsc,
                       type=job.type,
                       tank=job.tank,
                       command_line=job.command_line,
                       ammo_path=job.ammo_path,
                       loop_cnt=job.loop_cnt,
                       quit_status=job.quit_status,
                       test_type=job.test_type,
                       srv=job.srv,
                       srv_port=job.srv_port,
                       instances=job.instances,
                       flag=job.flag,
                       component=job.component,
                       ver=job.ver,
                       configinfo=job.configinfo,
                       finalized=job.finalized)
        d.save()

        cursor = connections['default'].cursor()
        sql = '''
                delete from regression_comment where job_id=%(job)s;
                '''
        cursor.execute(sql, {'job': job.n})
        cursor.close()

        LoadScheme.objects.filter(up=job).delete()

        job.delete()

        return 1
    except:
        logging.exception('')
        return 0
