import re

from common.models import Regression
from regression.util.stat_functions import get_functions_spec


def _is_valid_function(field, value, error):
    """
    Определяет, является ли переданная строка корректной функцией для схемы регрессии
    Необходимо, чтобы среди функций, возвращаемых get_functions_spec,
    не было пары функций, одна из которых является префиксом другой
    """
    not_parametrized_functions = [f['name'] for f in get_functions_spec() if not f['parametrized']]
    parametrized_functions = [f['name'] for f in get_functions_spec() if f['parametrized']]
    functions = parametrized_functions + not_parametrized_functions

    try:
        function_name, rest = value.split('(', 1)
        rest = '(' + rest
    except ValueError:
        function_name = value
        rest = ''

    is_parametrized_function = function_name in parametrized_functions
    is_not_parametrized_function = function_name in not_parametrized_functions

    if not is_not_parametrized_function and not is_parametrized_function:
        error(field, 'Function name should be one of {}'.format(functions))
    else:
        if is_not_parametrized_function:
            if rest:
                error(field, 'Function {} should not be parametrized'.format(function_name))
        else:
            regex = re.compile(r'\([^,]+(,[^,]+)*\)')
            if not re.fullmatch(regex, rest):
                error(field, 'Parametrized function {} is not properly defined'.format(function_name))


def _is_valid_name(current_name=None):
    def validator(field, value, error):
        queryset = Regression.objects.filter(name=value)
        if queryset.exists():
            if queryset.first().name == current_name:
                pass
            else:
                error(field, 'Name {} is already occupied'.format(value))
    return validator


REGRESSION_NAME_PATTERN = '[a-zA-Zа-яА-ЯёЁ0-9\._-]+'


def get_config_schema(current_name=None):
    return {
        'name': {
            'type': 'string',
            'empty': False,
            'required': True,
            'regex': r'^{}$'.format(REGRESSION_NAME_PATTERN),
            'check_with': _is_valid_name(current_name),
        },
        'meta': {
            'type': 'dict',
            'keysrules': {
                'type': 'string',
                'empty': False
            },
            'valuesrules': {
                'type': 'string',
                'empty': False
            },
            'default': {}
        },
        'group_by': {
            'type': 'string',
            'allowed': ['id', 'status', 'test_start'],
            'default': 'id'
        },
        'series_list': {
            'type': 'list',
            'schema': {
                'type': 'dict',
                'schema': {
                    'filter': {
                        'type': 'dict',
                        'required': True,
                        'keysrules': {
                            'type': 'string',
                            'empty': False
                        },
                        'valuesrules': {
                            'type': 'string',
                            'empty': False
                        }
                    },
                    'sla': {
                        'type': 'list',
                        'schema': {
                            'type': 'dict',
                            'schema': {
                                'name': {
                                    'type': 'string',
                                    'default': ''
                                },
                                'function': {
                                    'type': 'string',
                                    'check_with': _is_valid_function,
                                    'required': True
                                },
                                'ge': {
                                    'type': 'number'
                                },
                                'gt': {
                                    'type': 'number'
                                },
                                'le': {
                                    'type': 'number'
                                },
                                'lt': {
                                    'type': 'number'
                                }
                            }
                        },
                        'default': []
                    }
                }
            },
            'default': []
        },
        'test_ids': {
            'type': 'list',
            'schema': {
                'type': 'integer'
            },
            'default': []
        }
    }
