import logging
import re

from functools import reduce

from common.layout import common_layout
from common.widgets import Widget
from job_page.artifacts.logic import get_artifacts_list, get_configs_list
from job_page.artifacts.tank import TankAPIError


logger = logging.getLogger(__name__)


def _sort_widgets(widgets):
    """
    :type widgets: list of Widget
    :rtype: list of Widget
    """
    try:
        widgets_order = '^current[ @]*.*$', '^cpu-cpu.* ?@? ?.*', '^System ?@? ?.*$', '^Memory ?@? ?.*$', \
                        '^diskio- ?@? ?.*$'
        sorted_widgets = []
        for o in widgets_order:
            for w in widgets:
                if re.match(o, w.title):
                    sorted_widgets.append(widgets.pop(widgets.index(w)))
        sorted_widgets += sorted(widgets, key=lambda x: x.title)
        return sorted_widgets
    except:
        logging.exception('')
        return widgets


def _group_data(metrics, keys):
    """
    :type keys: list of string
    :type metrics: list of Data
    """
    groupped = {}
    for metric in metrics:
        group_key = tuple([metric.meta.get(key, metric.meta.get('name', 'untitled')) for key in keys]) \
            if len(keys) > 0 else (metric.meta.get('name', 'untitled'),)
        groupped[group_key] = groupped.get(group_key, []) + [metric]
    return groupped


def _get_widgets(groupped_data):
    widgets = [Widget(group_key, metrics) for group_key, metrics in
                groupped_data.items()]
    # with log_time_context(tag='GETTING FULL META'):  # дебажный логгинг.
    return widgets


def _filter_data(all_data, **kw):
    def filter_step(data_list, key_value):
        key, value = key_value
        return [d for d in data_list if d.meta.get(key) == value]

    return reduce(filter_step, kw.items(), all_data)


def _get_sections(job_obj):
    """
    :type job_obj: Job
    """
    SQL = """
        SELECT uniq_id, array_agg((key, value)) from data, data_meta
        WHERE job_id=%d AND data.id=data_meta.data_id
        GROUP BY uniq_id
    """
    # with connection.cursor() as cursor:
    #     cursor.execute(SQL, [job_obj.pk])
    #     rows = [(row[0], dict(row[1])) for row in cursor.fetchall()]
    sections_selector = {
        ('__type', 'tank'): [
            {'filter': {'importance': 'high'}, 'group_by': []},
            {'filter': {'type': 'monitoring'}, 'group_by': ['host', 'group']},
            {'filter': {'source': 'tank'}, 'group_by': []}]
    }
    DEFAULT_SECTION = {'filter': {}, 'group_by': []}
    for criterion, params in sections_selector.items():
        key, value = criterion
        if job_obj.meta.get(key) == value:
            sections_params = params
            break
    else:
        sections_params = [DEFAULT_SECTION]

    job_data = list(job_obj.data_set.all().prefetch_related('job__data_set__datameta_set'))

    return [{'widgets': [w.as_dict() for w in
                         _sort_widgets(
                             _get_widgets(
                                 _group_data(
                                     _filter_data(job_data, **section['filter']),
                                     section['group_by'])
                             )
                         )],
             'title': str(section['filter']), }
            for section in sections_params]


def render_layout(job_obj, meta, base_url):
    """

    :param luna_url: Luna url in form: http://luna.yandex-team.ru/
    :type job_obj: common.models.Job
    :return:
    """

    try:
        artifacts = get_artifacts_list(job_obj, base_url)
    except TankAPIError:
        artifacts = None

    try:
        configs = get_configs_list(job_obj, base_url)
    except TankAPIError:
        configs = None

    sections = _get_sections(job_obj)
    attributes = job_obj.attributes
    regressions = list(job_obj.regression_set.all().values_list('name', flat=True))

    return common_layout(sections=sections,
                         meta=meta,
                         attributes=attributes,
                         regressions=regressions,
                         artifacts=artifacts,
                         configs=configs)
