class ColourComponent:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __get__(self, instance, owner_class):
        # print(f'__get__ called')
        return int(instance.hex[self.start:self.end], 16)

    def __set__(self, instance, value):
        # print('__set__ called')
        pass

class Colour:
    r = ColourComponent(1, 3)
    g = ColourComponent(3, 5)
    b = ColourComponent(5, 7)

    def __init__(self, hex):
        self.hex = hex

def test_colour():
    colour = Colour('#ff8823')
    print(colour.r)
    print(colour.g)
    print(colour.b)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class MaxLengthAttribute:

    def __get__(self, instance, owner_class):
        if instance.__dict__ == {}:
            return None
        return sorted(instance.__dict__.keys(), key= lambda x: (len(x), x), reverse=True)[0]


class MyClass:
    max_length_attribute = MaxLengthAttribute()

class JustClass:
    max_atr = MaxLengthAttribute()


def test_len():

    # obj = MyClass()
    # obj.name = "Vasiliy"
    # obj.city = "Saint Peterburg"
    # obj.country = "Rus"
    # print(obj.max_length_attribute)

    obj = JustClass()
    obj.mock = 15
    obj.city = "Saint Peterburg"
    obj.name = "Vasiliy"
    obj.door = 'wood'
    print(obj.max_atr)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class RangeValidator:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.value = 0

    def __get__(self, instance, owner_class):
        pass 
    
    def __set__(self, instance, value):
        if not isinstance(value, (int, float)):
            raise TypeError('Неправильный тип данных')
        if value < self.start or value > self.end:
            raise ValueError(f'Значение должно быть между {self.start} и {self.end}')
        self.value = value

class Temperature:
    celsius = RangeValidator(-273.15, 1000)


def test_range_validator():
    temp = Temperature()
    try:
        temp.celsius = [1, 2]
    except TypeError as ex:
        print(ex)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class StringValidation:
    def __init__(self, min_length=None, max_length=None, 
                 exclude_chars=None, is_same_register=False):
        self.min_length = min_length
        self.max_length = max_length
        self.exclude_chars = exclude_chars
        self.is_same_register = is_same_register

    def __set_name__(self, owner_class, attribute_name):
        self.attribute_name = attribute_name

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError(f'В атрибут {self.attribute_name} можно сохранять только строки')
        
        if self.min_length is not None:
            if len(value) < self.min_length:
                raise ValueError(f'Длина атрибута {self.attribute_name} должна '
                                 f'быть не меньше {self.min_length} символов')
            
        if self.max_length is not None:
            if len(value) > self.max_length:
                raise ValueError(f'Длина атрибута {self.attribute_name} должна '
                                 f'быть не больше {self.max_length} символов')

        if self.exclude_chars is not None:
            for char in self.exclude_chars:
                if char in value:
                    raise ValueError(f'Имеются недопустимые символы в атрибуте {self.attribute_name}')

        if self.is_same_register == True:
            if not value.isupper() and not value.islower():
                                
                raise ValueError(f'Все буквы должны быть в одном регистре в атрибуте {self.attribute_name}')

        instance.__dict__[self.attribute_name] = value    

    def __get__(self, instance, owner_class):
        if instance is None:
            return self
        else:
            print(f'calling __get__ for {self.attribute_name}')
            return instance.__dict__.get(self.attribute_name, None)

class Person:
    '''
    name = StringValidation()
    last_name = StringValidation()
    '''
    '''
    name = StringValidation(min_length=10, exclude_chars='tyuio')
    last_name = StringValidation(max_length=5)
    '''
    name = StringValidation(is_same_register=True, exclude_chars='tyur')
    last_name = StringValidation(max_length=10, is_same_register=True)
    
def test_string_validation():
    
    '''
    p = Person()
    p.name = 'Michail'
    p.last_name = 'Lermontov'
    print(p.name, p.last_name)
    '''

    '''
    p = Person()
    try:
        p.name = 'Michail Second'
    except ValueError as ex:
        print(ex)

    try:
        p.last_name = 'Lermontov'
    except ValueError as ex:
        print(ex)
    print(p.name, p.last_name)
    '''

    p = Person()
    try:
        p.name = 'Michail Second'
    except ValueError as ex:
        print(ex)
    try:
        p.last_name = 'LERMONTOV'
    except ValueError as ex:
        print(ex)
    print(p.name, p.last_name)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


if __name__ == '__main__':
    # test_colour()
    # test_len()
    # test_range_validator()
    test_string_validation()