# -*- coding: utf-8 -*-

from wtforms.validators import DataRequired, Optional, ValidationError

from saas.tools.ssm.modules.abc_api import ABCApi
from saas.tools.ssm.modules.misc import collect_users_from_string


def split_count_string(string):
    for i, c in enumerate(string):
        if not c.isdigit():
            return string[:i], string[i:]


class RequiredIf(DataRequired):
    """
    Validator which makes a field required if another field. Also can works with list of values. See examples.
    Usage: validators=[RequiredIf(myfiled=['myvalue'], message='Hi there!')]
           validators=[RequiderIf(myfield=['myvalue1', 'myvalue2', 'myvalue3'], message='I works with any of values!']
    """
    field_flags = ('requiredif',)

    def __init__(self, message=None, **kwargs):
        super(RequiredIf, self).__init__(message=message)
        self.conditions = kwargs

    # field is requiring that name field in the form is data value in the form
    def __call__(self, form, field):
        for name, data in self.conditions.items():
            other_field = form[name]
            if other_field is None:
                raise Exception('no field named "%s" in form' % name)
            if other_field.data in data and not field.data:
                super(RequiredIf, self).__call__(form, field)
            Optional().__call__(form, field)


class TypeValidIf(object):
    """
    Validator which makes a field required if another field. Also can works with
    """
    field_flags = ('typeValidIf',)

    def __call__(self, form, field):
        if 'kv' in field.data and form.service_ctype.data == 'stable':
            raise ValidationError("Для указанного ctype поддерживается только тип сервиса search")
        if 'search' in field.data and form.service_ctype.data == 'stable_kv':
            raise ValidationError("Для указанного ctype поддерживается только тип сервиса key-value")
        if 'kv' not in field.data and 'kv' in form.service_ctype.data:
            raise ValidationError("Для указанного ctype поддерживается только тип сервиса key-value")
        if 'dj' not in field.data and 'dj' in form.service_ctype.data:
            raise ValidationError("Для указанного ctype поддерживается только тип сервиса dj")
        if 'dj' in field.data and not ('dj' not in form.service_ctype.data or 'zen' not in form.service_ctype.data):
            raise ValidationError("Для типа сервиса dj нужно использовать ctype, с суффиксами _dj и _zen")


class IntValidIf(object):
    """
    Compare other field compare value and if field value less than self field value, raise exception
    """
    field_flags = ('validIf',)

    def __init__(self, min_value, operator, message=None, **kwargs):
        self.message = message
        self.operator = operator
        self.min_value = min_value
        self.conditions = kwargs

    def __call__(self, form, field):
        for name, data in self.conditions.items():
            c_field = form[name]
            compare_string = str(c_field.data) + str(self.operator) + str(data)
            if eval(compare_string):
                if int(field.data) < self.min_value:
                    raise ValidationError(self.message)


class CountOf(object):
    """
    Compare other field compare value and if field value less than self field value, raise exception
    """
    field_flags = ('countOf',)

    def __init__(self, count_type, message=None):
        self.count_type = count_type
        self.message = message

    def __call__(self, form, field):
        # Check for digit value
        if not field.data.isdigit():
            num, substr = split_count_string(field.data)
            substr = substr.strip()
            # Check for only last character in field
            if not (substr.isalpha() and num.isdigit()):
                raise ValidationError(self.message)
            # Check count character
            if (('decimal' in self.count_type and substr.lower() not in ['k', 'm', 'b']) or
                    ('bytes' in self.count_type and substr.lower() not in ['k', 'm', 'g', 't', 'kb', 'mb', 'gb', 'tb'])):
                raise ValidationError(self.message)
        Optional().__call__(form, field)


class ABCParent(object):
    """
    Check for child ABC service in parent ABC service
    """
    field_flags = ('abcParent',)

    def __init__(self, abc_parent_id, message=None):
        self.abc_parent_id = abc_parent_id
        self.message = message

    def __call__(self, form, field):
        abc_client = ABCApi()
        abc_parent_service = form[self.abc_parent_id]
        if not abc_client.check_service_parent(field.data, abc_parent_service.data):
            raise ValidationError(self.message)


class ABCUser(object):
    """
    Check for user in ABC service
    """
    field_flags = ('abcUser',)

    def __init__(self, message=None):
        self.message = message

    def __call__(self, form, field):
        abc_client = ABCApi()
        login = form['user_login'].data
        allowed_logins = abc_client.get_logins_by_role(664, 'administration')
        if not abc_client.check_user_in_service(field.data, login) and login not in allowed_logins and login not in 'anonymous':
            raise ValidationError(self.message)


class StaffUser(object):
    """
    Check for user in ABD (user present in staff)
    """
    field_flags = ('staffUser',)

    def __call__(self, form, field):
        abc_client = ABCApi()
        logins = collect_users_from_string(field.data)
        for login in logins:
            if not abc_client.check_user_in_staff(login):
                raise ValidationError('Не могу найти пользователя {}, проверьте правильность написания логина'.format(login))
