from typing import List, Dict, Tuple, Set
from typing import Union
from typing import Optional


'''
Docstring - строка документирования.

Вызывается:

    help(abs)
    abs.__doc__

В docstring попадет только первая строка из начала функции.

Слабая и сильная (строгая) типизация.

В языках со строгой типизация (Python) с объектами определенных
типов можно производить только ограниченный набор действий.

В Python динамическая строгая типизация.


        Аннотация типов в Python

foo: float        

foo: int = 100

В функции содержится атрибут __annotations__ (содержит словарь аннотаций)


'''

def get_even(lst) -> list:
    'Функция возвращает список из четных чисел списка lst'
    even_lst = []
    for elem in lst:
        if elem % 2 == 0:
            even_lst.append(elem)
    return even_lst


def func_1():
    numbers: List[int] = [1, 2, 3]
    languages: Dict = {}
    temperature: Tuple = (1, 2, 3)
    letters: Set[str] = set('qwerty')

    param_1: Union[int, float, bool]

    param_2: int | float | str


def get_first_repeated_word(words: List[str]) -> Optional[str]:
    'Находит первый дубль в списке'
    foo = set()
    for w in words:
        if w in foo:
            return w
        else:
            foo.add(w)
    return None


def rotate(lst: list[int | float], shift: int = 1) -> list[int | float] :
    'Функция выполняет циклический сдвиг списка на shift позиций вправо(shift>0) или влево(shift<0)'
    shifted_list = []

    if abs(shift) <= len(lst) or shift%len(lst) == 0:
        foo = shift
    else:
        if shift < 0:
            foo = abs(shift)%len(lst)
            foo *= -1
        else:
            foo = shift%len(lst)

    if foo < 0:
        shifted_list.extend(lst[-foo:])
        shifted_list.extend(lst[:-foo])
    elif foo > 0:
        shifted_list.extend(lst[-foo:])
        shifted_list.extend(lst[:-foo])
    return shifted_list


def ref_rotate(tpl: tuple[int | float, ...], shift: int = 1) -> tuple[int | float, ...] :
    'Функция выполняет циклический сдвиг кортежа на shift позиций вправо (shift>0) или влево (shift<0)'
    shifted_tuple = tuple()

    if abs(shift) <= len(tpl) or shift%len(tpl) == 0:
        foo = shift
    else:
        if shift < 0:
            foo = abs(shift)%len(tpl)
            foo *= -1
        else:
            foo = shift%len(tpl)

    if foo < 0:
        shifted_tuple = tpl[-foo:] + tpl[:-foo]
    elif foo > 0:
        shifted_tuple = tpl[-foo:] + tpl[:-foo]
    return shifted_tuple


def rotate_letter(letter: str, shift: int) -> str :
    'Функция сдвигает символ letter на shift позиций'

    code = ord(letter) - 97

    if shift >= 0:
        shift = shift - 26*(shift//26)
        if (code + 97 + shift) >= 122:
            return chr(code + 97 + shift - 26)
        else:
            return chr(code + 97 + shift)
    else:
        shift *= -1
        shift = shift - 26*(shift//26)
        if (code + 97 - shift) < 97:
            return chr(code + 97 + 26 - shift)
        else:
            return chr(code + 97 - shift)


def caesar_cipher(phrase: str, key: int) -> str:
    'Шифр Цезаря'

    my_str = ""
    for i in phrase:
        if i.isalpha():
            my_str += rotate_letter(i, key)
        else :
            my_str += i
    return my_str




def main():
    # print(get_even.__doc__)
    # print(get_first_repeated_word.__doc__)
    # print(get_first_repeated_word.__annotations__)
    # print(get_first_repeated_word(['ab', 'ca', 'bc', 'ca', 'ab', 'bc']))

    # print(rotate([1, 2, 3, 4, 5, 6], 2))
    # print(rotate([1, 2, 3, 4, 5, 6], -10))
    # print(rotate([1, 2, 3, 4, 5, 6, 7], 21))
    # print(rotate([1, 2, 3, 4, 5, 6], -3))

    # assert rotate([1, 2, 3, 4, 5, 6], 2) == [5, 6, 1, 2, 3, 4]
    # assert rotate([1, 2, 3, 4, 5, 6], -3) == [4, 5, 6, 1, 2, 3]
    # assert rotate([1, 2, 3, 4, 5, 6], -10) == [5, 6, 1, 2, 3, 4]
    # assert rotate([1, 2, 3, 4, 5, 6, 7], 21) == [1, 2, 3, 4, 5, 6, 7]

    # print(rotate_letter('a', 3))
    # print(rotate_letter('d', -2))
    # print(rotate_letter('w', -26))

    print(caesar_cipher('leave out all the rest', -4))

    print('Good')

if __name__ == '__main__':
    main()