# -*- coding: utf-8 -*-
"""
Created on Jul 26, 2013

@author: noob
"""
from .plots.dist_plots import TimesDistPlot, QuantilesVsTimes, QuantilesVsRps, QuantilesVsInstanses, \
    AvgTimesVsRps, AvgTimesVsInstanses
from .plots.monitoring_plots import MonitoringCPUPlot, MonitoringCustomPlot, MonitoringDiskPlot, MonitoringMemoryPlot, \
    MonitoringNetPlot, MonitoringSystemPlot, MonitoringPlot, TelegrafCPUPlot, TelegrafDiskPlot, TelegrafNetPlot
from .plots.tables import CasesDistTable, CasesNetCodesTable, CasesHttpCodesTable, CasesCumulativeQuantilesTable, \
    QuantilesCumulativeTable, TimesDistTable, MonitoringAggregatesTable, HttpDistTable, NetDistTable, \
    AggregatesTable, MultitagCumulativeQuantilesTable, MultitagHttpCodesTable, MultitagNetCodesTable, \
    MultitagDistTable
from .plots.timeline_plots import QuantilesTimelinePlot, HTTPCodesTimelinePlot, NetCodesTimelinePlot, \
    AvgTimesTimelinePlot, InstancesTimelinePlot, \
    SentReceivedPlot, CasesTimelinePlot, CasesAvgTimelinePlot, TimesDistTimelinePlot
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseServerError
from django.utils.datastructures import MultiValueDictKeyError
from json import dumps
import logging

PLOT_TYPE_MAPPING = {'quantiles_timeline_plot': QuantilesTimelinePlot,
                     'http_timeline_plot': HTTPCodesTimelinePlot,
                     'net_timeline_plot': NetCodesTimelinePlot,
                     'times_dist_table': TimesDistTable,
                     'cases_avg_timeline_plot': CasesAvgTimelinePlot,
                     'timesdist_timeline_plot': TimesDistTimelinePlot,
                     'cases_timeline_plot': CasesTimelinePlot,
                     'avgtimes_timeline_plot': AvgTimesTimelinePlot,
                     'sent_received_plot': SentReceivedPlot,
                     'instanses_timeline_plot': InstancesTimelinePlot,

                     'times_dist_plot': TimesDistPlot,
                     'quantiles_vs_times': QuantilesVsTimes,
                     'quantiles_vs_rps': QuantilesVsRps,
                     'quantiles_vs_instanses': QuantilesVsInstanses,

                     'cases_dist_table': CasesDistTable,
                     'cases_netcodes_table': CasesNetCodesTable,
                     'cases_httpcodes_table': CasesHttpCodesTable,
                     'cases_cumulative_quantiles_table': CasesCumulativeQuantilesTable,
                     'multitag_dist_table': MultitagDistTable,
                     'multitag_cumulative_quantiles_table': MultitagCumulativeQuantilesTable,
                     'multitag_httpcodes_table': MultitagHttpCodesTable,
                     'multitag_netcodes_table': MultitagNetCodesTable,
                     'http_dist_table': HttpDistTable,
                     'net_dist_table': NetDistTable,
                     'quantiles_cumulative_table': QuantilesCumulativeTable,
                     'aggregates_table': AggregatesTable,
                     'avgtimes_vs_rps': AvgTimesVsRps,
                     'avgtimes_vs_instanses': AvgTimesVsInstanses,

                     'monitoring_net_plot': MonitoringNetPlot,
                     'monitoring_disk_plot': MonitoringDiskPlot,
                     'monitoring_memory_plot': MonitoringMemoryPlot,
                     'monitoring_cpu_plot': MonitoringCPUPlot,
                     'monitoring_system_plot': MonitoringSystemPlot,

                     'monitoring_aggregates_table': MonitoringAggregatesTable,
                     }

TABLES = ['CasesDistTable', 'CasesNetCodesTable', 'CasesHttpCodesTable', 'CasesCumulativeQuantilesTable',
          'QuantilesCumulativeTable', 'TimesDistTable', 'MonitoringAggregatesTable', 'HttpDistTable', 'NetDistTable',
          'AggregatesTable', 'MultitagCumulativeQuantilesTable', 'MultitagHttpCodesTable', 'MultitagNetCodesTable',
          'MultitagDistTable']
DISTS = ['TimesDistPlot', 'QuantilesVsTimes', 'QuantilesVsRps', 'QuantilesVsInstanses',
         'AvgTimesVsRps', 'AvgTimesVsInstanses']


def get_plot_chunk(request, job):
    """
    FOR REFRESHING EXISTING CHARTS
    :param request:
    :param job:
    """

    try:
        plot_types = [p for p in request.GET['plot_types'].split(',') if
                      p and not p.startswith('monitoring') or p.startswith('monitoring_aggregates_table')]
        monitoring_plot_types = [mp for mp in request.GET['plot_types'].split(',') if
                                 mp.startswith('monitoring') and not mp.startswith('monitoring_aggregates_table')]
        latest_second = request.GET.get('latest_second', 0) or 0
        latest_second = int(latest_second) // 1000
        interval = request.GET.get('interval', 0) or 0
        compress_ratio = int(request.GET.get('compress_ratio', 0)) or 1
    except (MultiValueDictKeyError, TypeError):
        logging.exception('BadRequest')
        return HttpResponseBadRequest('')
    tag = request.GET.get('tags', '')
    try:
        data = {}
        for plot_type in plot_types:
            try:  # So if one plot is erroneous it wont fail all of them
                if plot_type.startswith('monitoring_aggregates_table@'):
                    plot = PLOT_TYPE_MAPPING[plot_type.split('@')[0]](job, latest_second, interval, compress_ratio,
                                                                      plot_type.split('@')[1])
                else:
                    plot = PLOT_TYPE_MAPPING[plot_type](job, latest_second, interval, compress_ratio, tag)
                if plot.__class__.__name__ not in TABLES + DISTS:
                    plot.get_times_and_scheme()
                data[plot_type] = plot_chunk(plot, latest_second)
            except:
                logging.exception('')
                data[plot_type] = {}
        if monitoring_plot_types:  # OMMFG
            targets = list(set(mp.split('@')[1] for mp in monitoring_plot_types))
            for target in targets:
                monitoring_chunk = MonitoringPlot(job, latest_second, interval, compress_ratio, target).chunk
                for mp in monitoring_plot_types:
                    try:  # So if one plot is erroneous it wont fail all of them

                        plot_args = (job, latest_second, interval, compress_ratio, target)
                        custom_metric = '_'.join(mp.split('@')[0].split('_')[1:-1])

                        if mp.split('_')[1].split(':')[0][0:-1].lower() == 'custom':
                            m_plot = MonitoringCustomPlot(*plot_args, custom_metric=custom_metric)
                        elif mp.startswith('telegraf'):
                            if mp.split(':')[1].lower().startswith('cpu-cpu'):
                                m_plot = TelegrafCPUPlot(*plot_args, custom_metric=custom_metric)
                            elif mp.split(':')[1].lower().startswith('diskio-'):
                                m_plot = TelegrafDiskPlot(*plot_args, custom_metric=custom_metric)
                            elif mp.split(':')[1].lower().startswith('net-'):
                                m_plot = TelegrafNetPlot(*plot_args, custom_metric=custom_metric)
                            else:
                                m_plot = MonitoringCustomPlot(*plot_args, custom_metric=custom_metric)
                        else:
                            m_plot = PLOT_TYPE_MAPPING[mp.split('@')[0]](*plot_args)
                        m_plot.get_times()
                        m_plot_chunk = {
                            graph.split(':', 1)[1]
                            if m_plot.custom_metric and m_plot.custom_metric.startswith('customs__')
                            else '_'.join(graph.split('_')[1:]):
                                {'values': monitoring_chunk[int(m_plot.metrics_dict[graph])],
                                 'name': graph.split(':', 1)[
                                     1] if m_plot.custom_metric and m_plot.custom_metric.startswith(
                                     'customs__') else '_'.join(graph.split('_')[1:]),
                                 'type': m_plot.series_types_mapping(graph),
                                 'color': m_plot.color_mapping(graph)
                                 }
                            for graph in m_plot.graphs if graph
                        }
                        data[mp] = {'latestSecond': max(m_plot.times) * 1000 if m_plot.times else latest_second * 1000,
                                    'xAxis': [int(t) * 1000 for t in monitoring_chunk['xAxis']],
                                    'overrides': m_plot.overrides,
                                    'data': m_plot_chunk}
                    except KeyError:
                        logging.error('KeyError:', exc_info=True)
                        data[mp] = {'latestSecond': max(m_plot.times) * 1000 if m_plot.times else latest_second * 1000,
                                    'xAxis': [int(t) * 1000 for t in monitoring_chunk['xAxis']],
                                    'overrides': m_plot.overrides,
                                    'data': {}}
                    except:
                        logging.exception('')
                        data[mp] = {'latestSecond': max(m_plot.times) * 1000 if m_plot.times else latest_second * 1000,
                                    'xAxis': [int(t) * 1000 for t in monitoring_chunk['xAxis']],
                                    'overrides': m_plot.overrides,
                                    'data': {}}
        try:
            data['latestSecond'] = min(plot['latestSecond'] for plot in list(data.values()) if plot['latestSecond'])
        except:
            data['latestSecond'] = latest_second * 1000
        return HttpResponse(dumps(data), content_type='application/json')
    except:
        logging.exception('')
        return HttpResponseServerError('')


def plot_chunk(plot_obj, latest_second):
    try:
        if plot_obj.__class__.__name__ in TABLES:
            columns = plot_obj.get_columns()
            data = {
                'title': plot_obj.title,
                'subtitle': plot_obj.subtitle,
                'table': plot_obj.table,
                'overrides': plot_obj.overrides,
                'data': {
                    'header': [{'title': c['title'],
                                'align': c['align']}
                               for c in columns],
                    'rows': plot_obj.rows,
                    'columns': columns,
                },
            }
        else:
            data = {'latestSecond': get_latest_second(plot_obj, latest_second),
                    'xAxis': get_xaxis(plot_obj),
                    'overrides': plot_obj.overrides,
                    'data': get_chunk_data(plot_obj)}
        return data
    except:
        logging.exception('Could not get plot {} series_data for job {} due to:'.format(plot_obj.__class__.__name__,
                          plot_obj.job))
        return {'xAxis': [], 'data': {}, 'latestSecond': latest_second * 1000}


def get_latest_second(plot, latest_second):
    return max(
        plot.times) * 1000 if plot.__class__.__name__ not in TABLES + DISTS and plot.times else latest_second * 1000


def get_xaxis(plot):
    return [int(t) * 1000 for t in plot.times] if plot.__class__.__name__ not in TABLES + DISTS else plot.overrides[
        'xAxis']


def get_chunk_data(plot):
    return plot.get_chunk()
