#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import re
import logging
from datetime import datetime
from typing import Union, Mapping

from django.http import HttpResponseBadRequest, HttpResponseGone, HttpResponseNotFound

from common.models import Job, DeletedJob
from common.util.meta import escape_string
from common.util.clients import ClickhouseClient
from .base import Api


class JobTrailPush(Api):
    http_method_names = ['post']

    def dispatch(self, request, *args, **kwargs):
        args = list(args)
        self.job_n = args[0]

        # @cached('job_%s_fd' % self.job_n)
        def get_fd():
            return datetime.strftime(Job.objects.get(n=self.job_n).fd, '%Y-%m-%d')

        # @cached('job_%s_td' % self.job_n)
        def get_td():
            return bool(Job.objects.get(n=self.job_n).td)

        try:
            self.job_fd = get_fd()
            self.job_td = get_td()
        except Job.DoesNotExist:
            deleted = False
            if DeletedJob.objects.filter(n=self.job_n):
                deleted = True
                msg = 'Job had been deleted'
            else:
                msg = 'Job not found'

            if args[-1] == 'json':
                if deleted:
                    return HttpResponseGone(
                        json.dumps([{
                            'success': False,
                            'error': msg,
                            'msg': msg,  # backwards compatibility
                        }]),
                        content_type='application/json')
                else:
                    return HttpResponseNotFound(
                        json.dumps([{
                            'success': False,
                            'error': msg,
                            'msg': msg,  # backwards compatibility
                        }]),
                        content_type='application/json')
            else:
                if deleted:
                    return HttpResponseGone(msg)
                else:
                    return HttpResponseNotFound(msg)
        return super(JobTrailPush, self).dispatch(request, *args, **kwargs)

    def post(self, request, *args):
        """
        :param request: HTTP request
        :param job: job object passed from request
        """
        params = request.body.decode('utf-8')  # POST.get('item')
        if not params:
            return HttpResponseBadRequest('POST data is missing')
        params = json.loads(params)
        if isinstance(params, dict):
            params = [params]
        self.insert_items(params)
        # try:
        #     imbalance_finder = ImbalanceFinder(job, params)
        #     imbalance_finder.dispatch()
        # except AssertionError:
        #     pass
        # except:
        #     logging.exception('')

        return [{'success': 1}]

    def insert_items(self, items: Union[Mapping]) -> None:
        # TODO: remake tank datauploader
        # This is stupid, but it's the only way to support singlequotes in tags;
        rt_details_data = ["('%s', %s, '%s', '%s', %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
            self.job_fd,
            int(self.job_n),
            escape_string(item['case']),
            int(item['trail']['time'])
            if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
            else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'),
            int(item['trail']['connect_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['send_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['latency'] * item['trail']['resps'] * 1000),
            int(item['trail']['receive_time'] * item['trail']['resps'] * 1000),
            int(item['trail']['reqps']),
            int(item['trail']['resps']),
            int(item['trail']['threads']),
            int(item['trail']['input']),
            int(item['trail']['output']),
            0,
        )
                           for item in items
                           ]
        rt_quantiles_data = ["('%s', %s, '%s', '%s', %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
            self.job_fd,
            int(self.job_n),
            escape_string(item['case']),
            int(item['trail']['time'])
            if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
            else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'),
            float(item['trail']['q50']),
            float(item['trail']['q75']),
            float(item['trail']['q80']),
            float(item['trail']['q85']),
            float(item['trail']['q90']),
            float(item['trail']['q95']),
            float(item['trail']['q98']),
            float(item['trail']['q99']),
            float(item['trail']['q100']),
        )
                             for item in items
                             ]
        net_codes_data = []
        proto_codes_data = []
        rt_histograms_data = []
        for item in items:
            if item['net_codes']:
                net_codes_data.extend([
                    "('%s', %s, '%s', '%s', %s, %s)" %
                    (
                        self.job_fd,
                        int(self.job_n),
                        escape_string(item['case']),
                        int(item['trail']['time'])
                        if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                        else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                               '%Y-%m-%d %H:%M:%S'),
                        int(net_codes['code']),
                        int(net_codes['count']),
                    )
                    for net_codes in item['net_codes']
                ])
            if item['http_codes']:
                proto_codes_data.extend([
                    "('%s', %s, '%s', '%s', %s, %s)" % (
                        self.job_fd,
                        int(self.job_n),
                        escape_string(item['case']),
                        int(item['trail']['time'])
                        if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                        else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                               '%Y-%m-%d %H:%M:%S'),
                        int(proto_codes['code']),
                        int(proto_codes['count']),
                    )
                    for proto_codes in item['http_codes']
                ])
            if item['time_intervals']:
                rt_histograms_data.extend([
                    "('%s', %s, '%s', '%s', %s, %s)" % (
                        self.job_fd,
                        int(self.job_n),
                        escape_string(item['case']),
                        int(item['trail']['time'])
                        if str(item['trail']['time']).isdigit() or isinstance(item['trail']['time'], float)
                        else datetime.strftime(datetime.strptime(item['trail']['time'], '%Y-%m-%d %H:%M:%S'),
                                               '%Y-%m-%d %H:%M:%S'),
                        int(float(time_intervals['to']) * 1000),
                        int(time_intervals['count']),
                    )
                    for time_intervals in item['time_intervals']
                ])

        ch_client = ClickhouseClient()

        if rt_details_data:
            insert_rt_details_query = 'insert into loaddb.rt_microsecond_details_buffer values %s' % ','.join(
                t for t in rt_details_data)
            ch_client.insert(insert_rt_details_query)
        if rt_quantiles_data:
            insert_rt_quantiles_query = 'insert into loaddb.rt_quantiles_buffer values %s' % ','.join(
                t for t in rt_quantiles_data)
            ch_client.insert(insert_rt_quantiles_query)
        if net_codes_data:
            insert_net_codes_query = 'insert into loaddb.net_codes_buffer values %s' % ','.join(
                t for t in net_codes_data)
            ch_client.insert(insert_net_codes_query)
        if proto_codes_data:
            insert_proto_codes_query = 'insert into loaddb.proto_codes_buffer values %s' % ','.join(
                t for t in proto_codes_data)
            ch_client.insert(insert_proto_codes_query)
        if rt_histograms_data:
            insert_rt_histograms_query = 'insert into loaddb.rt_microsecond_histograms_buffer values %s' % ','.join(
                t for t in rt_histograms_data)
            ch_client.insert(insert_rt_histograms_query)

        ch_client.session.close()
