# Базовый синтаксис декоратора в python

def my_decorator(func):

    def wrapper_func():
        # Делаем что-то до вызова функции
        func()
        # Делаем что-то после вызова функции

    return wrapper_func


'''
def decorator(func):
    def wrapper():
        print('Start decorator')
        func()
        print('Finish decorator')
    return wrapper
'''

def decorator(func):
    def inner(*args, **kwargs):
        print('Стартуем декоратор')
        func(*args, **kwargs)
        print('Заканчиваем декоратор')
    return inner


def decorator_2(func):
    def inner(*args, **kwargs):
        print('Стартуем декоратор')
        func_res = func(*args, **kwargs)
        print(f'Функция func вернула значение "{func_res}"')
        print('Заканчиваем декоратор')
        return func_res.swapcase()
    return inner


@decorator_2
def say_hello_to(name, surname):
    return f'Hello {name} {surname}'


decorator
def my_func():
    print('This is my mega function!')


def header_h1(func):
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        return f'<h1>{result}</h1>'
    return inner

@header_h1
def one_more_func(name, surname):
    return f'Hello {name} {surname}'


def repeater(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        func(*args, **kwargs)
        func(*args, **kwargs)
    return wrapper


def text_decor(func):
    def inner(*args, **kwargs):
        print('Hello')
        return func(*args, **kwargs)
        print('Goodbye!')
    return inner

@text_decor
def multiply(num1, num2):
    print(num1 * num2)


def double_it(func):
    '''Декоратор возвращает удвоенный результат вызова декорируемой функции'''
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        return res * 2
    return inner


@double_it
def get_sum_kwargs_values(**kwargs):
    return sum(kwargs.values())


def uppercase_elements(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        if isinstance(res, dict):
            my_dict = {}
            for key, value in res.items():
                if isinstance(key, str):
                    my_dict[key.upper()] = value
                else:
                    my_dict[key] = value
            return my_dict
        else:
            my_list = []
            for x in res:
                if isinstance(x, str):
                    my_list.append(x.upper())
                else:
                    my_list.append(x)
            return my_list

            # return {key:value for key, value in res.items()}

    return inner
 

@uppercase_elements
def foo_1(**kwargs):
    return {1: 'one', 2: 'store', 'three': 3, 'four': 4} | kwargs


@uppercase_elements
def my_func():
    return ['monarch', 'Touch', 'officiaL', 'DangerouS', 'breathe']


def first_validator(func):
    def my_wrapper(*args, **kwargs):
        print(f"Начинаем важную проверку")
        if len(args) == 3:
            func(*args, **kwargs)
        else:
            print(f"Важная проверка не пройдена")
            return None
        print(f"Заканчиваем важную проверку")
    return my_wrapper


def second_validator(func):
    def my_wrapper(*args, **kwargs):
        print(f"Начинаем самую важную проверку")
        if kwargs.get('name') == 'Boris':
            func(*args)
        else:
            print(f"Самая важная проверка пройдена")
            return None
        print(f"Заканчиваем самую важную проверку")
    return my_wrapper


@second_validator
@first_validator
def sum_values(*args):
    print(f'Получили результат равный {sum(args)}')


def validate_all_args_str(func):
    def wrapper(*args, **kwargs):
        if len([True for x in args if type(x) == str]) == len(args):
            return func(*args, **kwargs)
        else:
            print('Все аргументы должны быть строками')
    return wrapper        


def validate_all_kwargs_int_pos(func):
    def wrapper(*args, **kwargs):
        if len([True for val in kwargs.values() if isinstance(val, int) and val > 0]) == len(kwargs):
            return func(*args, **kwargs)
        else:
            print("Все именованные аргументы должны быть положительными числами")
    return wrapper


def filter_even(func):
    def wrapper(*args, **kwargs):
        my_list = []
        for val in args:
            if isinstance(val, int):
                if val%2 == 0:
                    my_list.append(val)
            if (isinstance(val, (str, list, tuple, dict))):
                if len(val)%2 == 0:
                    my_list.append(val)
        return func(*my_list, **kwargs)
    return wrapper


def delete_short(func):
    def wrapper(*args, **kwargs):
        my_dict = {}
        for key, value in kwargs.items():
            if len(key) > 4:
                my_dict[key] = value
        return func(*args, **my_dict)
    return wrapper


@filter_even
@delete_short
def concatenate(*args, **kwargs):
    result = ""
    for arg in args + tuple(kwargs.values()):
        result += str(arg)
    return result





def main():

    print(concatenate("Я", "хочу", "Выучить", "Питон", a="За", qwerty=10, c="Месяцев"))

    # res = say_hello_to('Vasya', 'Ivanov')
    # print(f'{res=}')

    # res = one_more_func("gennadi", "LOSKOV")
    # print(f'{res=}')
   
#    print(multiply(3, 5))

    # print(get_sum_kwargs_values(a=4, b=5, d=3, t=6, r=8))
    
    # print(foo_1(**{'Five': 5, 'sIx': 6}))
    # print(my_func())

    # sum_values(70, 1, 6, name='Boris')

    # print(concatenate("Ну", "Когда", "Уже", "Я", "Выучу", "Питон?"))
    # print(concatenate(a="Я", b="Выучу", c="Этот", d="Питон", e="!"))
    # print(concatenate(a=10, b=20, c=50))


if __name__ == '__main__':
    main()