# flake8: noqa
# ------------------------------------------------------
# Небольшой блок подготовки.
# Тут нет проверок ролей, тут только определение функций
# ------------------------------------------------------

# Персональное и групповое воркфлоу должны быть одинаковыми.
# Если нужны отличия, надо использовать переменную is_personal_wf
is_personal_wf = 'user' in locals() and user is not None

# Заглушка, пока не починится https://st.yandex-team.ru/IDM-11299
try:
    request_type
except Exception:
    # Меняя тут переменную, можно проверять сценарий отрыва роли
    request_type = REQUEST_TYPE.REQUEST
    # request_type = REQUEST_TYPE.DEPRIVE


class RoleChecker(object):
    """
    Класс для проверки типа роли и её атрибутов
    При создании объектов, надо указать тип роли и перечень ее атрибутов.
    В качестве заначений атрибутов можно указывать список.

    В результате чего вместо
    if role['type'] == 'groups' and role['group'] in ['1', '2'] and role['role'] == 'responsible':
    Можно писать
    is_groups = RoleChecker('groups', 'group', 'role')
    if is_groups(group=['1', '2'], role='responsible')
    """

    def __init__(self, role_type, *attrs):
        self.type = role_type
        self.attrs = attrs

    def _check_attr(self, attr_name, value, role):
        if value is not None:
            value = value if isinstance(value, (list, tuple)) else [value]
            if not role[attr_name] in value:
                return False
        return True

    def __call__(self, role_obj, **kwargs):
        if not role_obj['type'] == self.type:
            return False

        for attr_name in self.attrs:
            if not self._check_attr(attr_name, kwargs.get(attr_name), role_obj):
                return False
        return True


is_groups = RoleChecker('groups', 'group', 'role')
is_robots = RoleChecker('robots', 'robot', 'role')
is_user_attrs = RoleChecker('user_attrs', 'user_attr')
is_department_roles = RoleChecker('department_roles', 'department', 'role')

approvers = None

# -------------------------------------------
# Блок с проверками. Все условия, которые касаются определенных типов ролей надо начинать с проверочной функции выше.
# ---------------------------------------------------

staff_team = any_from(list(groupify('svc_support_services_management').members), priority=3) | approver('rchernitsyn',
                                                                                                        priority=4)
super_users = system.all_users_with_role({'type': 'user_attrs', 'user_attr': 'is_superuser'})
staff_products = [approver('dmirain', priority=2) | approver('rchernitsyn', priority=1)]


def security_team():
    return groupify(147719).members


if is_user_attrs(role) or is_department_roles(role):
    approvers = staff_products
    if is_department_roles(role, role='H'):  # HR-партнёр
        if is_personal_wf == False:
            raise AccessDenied(u'Роль HR BP  не выдается на группу')
        head = user.get_boss()
        if any(r['type'] == 'department_roles' and r['role'] == 'H' for r in head.all_roles):
            approvers = approver(head, priority=1) | approver('elena-bo', priority=2)
        else:
            approvers = approver('elena-bo', priority=1)
    if is_department_roles(role, role='A'):  # HR-аналитик
        approvers = [any_from(['ishiryaeva', 'evgpopkova', 'ekvoloboy'], priority=1),
                     approver('angelina-iln', priority=2)]
    if is_department_roles(role, role='HEADCOUNT_VIEWER'):  # Смотритель хэдкаунта
        approvers = any_from(['tanyakz', 'ekvoloboy', 'evgpopkova', 'ishiryaeva'], priority=1)
    if is_department_roles(role, role='AT'):  # Временная роль (ха) HR-аналитика
        approvers = [
            approver('dmirain', priority=2) | approver('rchernitsyn', priority=2) | approver('tanyakz', priority=1)]
    if is_department_roles(role, role='RECRUITMENT_PARTNER'):  # Рекрутмент-партнер
        approvers = approver('ekemelina', priority=1) | approver('rchernitsyn', priority=2)
    if is_department_roles(role, role='RECRUITMENT_VACANCY_VIEWER'):  # Рекрутмент-партнер
        approvers = approver('ekemelina', priority=1) | approver('rchernitsyn', priority=2)
    if is_department_roles(role, role='FINCAB_VIEWER'):  # Смотритель нового фин. кабинета
        approvers = approver('katerinakam', priority=1) | approver('chudosveta', priority=1) | approver('ishiryaeva',
                                                                                                        priority=1)
    if is_department_roles(role, role='FUNCTIONAL_CHIEF'):  # https://st.yandex-team.ru/STAFF-15555
        approvers = approver('bunina', priority=1)
    if is_department_roles(role, role='MA'):  # https://st.yandex-team.ru/STAFF-15716
        approvers = approver('korshevam', priority=1)

    oficer_roles = [
        'PROJECT_PORTFOLIO_MANAGER',
        'TECH_LEAD_MANAGER',
        'MARKETING_MANAGER',
        'BUSINESS_DEVELOPMENT_MANAGER',
        'MEMBER_OF_THE_EXPERT_COUNCIL',
        'CURATOR_EXPERIMENT',
        'CURATOR_BU',
    ]
    if is_department_roles(role, role=oficer_roles):  # https://st.yandex-team.ru/STAFF-14703
        approvers = approver('alexeysmirnov', priority=1) | approver('oxanapudova', priority=1) | approver('styskin',
                                                                                                           priority=2)

if is_department_roles(role, role=['EXT_WITH_STAFF_PROFILE_ACCESS', 'EXT_WITH_STAFF_DEPARTMENT_ACCESS',
                                   'EXT_WITH_GAP_ACCESS']):
    dep = groupify(role['department'])
    ancestors_url = {anc.slug for anc in dep.get_ancestors()}
    up_to_level = 3 if {'yandex', 'yandex_money'} & ancestors_url else 1
    heads = dep.get_chain_of_heads(up_to_level=up_to_level)
    if is_personal_wf and user.username == 'imperator':
        approvers = approver('tokza', priority=1)
    else:
        protected_deps = ['yandex', 'outstaff', 'yandex_money', 'ext', 'yandex_main_searchadv', 'yandex_bu',
                          'yandex_exp', 'yandex_biz_com', 'yandex_edu', 'yandex_dep32124', 'yandex_gen', 'yandex_5617',
                          'yandex_legal_state']
        if role['department'] in protected_deps:
            approvers = (heads | any_from(super_users, priority=3)), any_from(security_team(), priority=1)
        else:
            approvers = (heads | any_from(super_users, priority=3))

if is_department_roles(role, role='EXTERNAL_WITH_STAFF_FULL_ACCESS'):
    raise AccessDenied(
        'Для выдачи доступа на Стафф "внешним" сотрудникам воспользуйтесь инструкцией: https://wiki.yandex-team.ru/staff/vodstvo/zapros-dostupa-na-staff-dlja-vneshnix-sotrudnikov/ ')

if is_department_roles(role, role='EXTERNAL_WITH_STAFF_FULL_ACCESS'):
    if is_personal_wf and user.username == 'imperator':
        approvers = approver('tokza', priority=1)
    else:
        approvers = any_from(security_team())

# Переходим на Ресурсы в ABC
# ABC-8036: запрещено запрашивать роли роботов всем, кроме робота из ABC
# и твм-приложения abc (ABC-6823)
if is_robots(role, role='owner'):
    if requester.username == 'zomb-prj-282' or requester.username == '2012190':
        approvers = []
        raise Return()
    elif request_type == REQUEST_TYPE.REQUEST:
        raise AccessDenied(
            'Для получении роли владельца робота воспользуйтесь инструкцией https://wiki.yandex-team.ru/intranet/abc/features/robots/ ')

elif is_robots(role):
    responsibles = system.all_users_with_role(dict(role, role='owner'))
    approvers = any_from(responsibles, priority=1) | staff_team

if is_groups(role):
    responsibles = system.all_users_with_role(dict(role, role='responsible'))

    # Группы которые надо отправлять только ответственным
    resp_groups = [
        '34527',  # vertislogger
        '40191',  # vertismysqlreadonly
        '760',  # SearchSpam
        '761',  # SearchVirus
        '38364',  # animals
        '36191',  # группа управления динамическим файерволлом
        '42935',  # atushka_dostup
        '219626',  # отчёт об уволенных со стаффа
    ]
    if is_groups(role, group=resp_groups, role='member'):
        approvers = any_from(responsibles, priority=1)
    else:
        approvers = any_from(responsibles, priority=1) | staff_team

if is_groups(role, role='responsible') or is_robots(role, role='owner'):
    ref_roles = [{
        'system': 'self',
        'role_data': {'group': 'system', 'system_on': 'staff', 'role': 'roles_manage'},
        'role_fields': {'scope': scope}
    }]

# запрос связанных ролей из доверенных систем не требует одобрения (STAFF-13972)
trusted_systems = {'oebs', 'hyperion', 'fcm', 'bi'}
oebs_linked_groups = [  # группы, соответствующие связанным ролям в системе OEBS
    '185685',  # OEBS-FINANCE-INFO
    '187543',  # OEBS-PO-INFO
    '187545',  # OEBS-AT-INFO
    '187544',  # OEBS-HR-INFO
    '187546',  # MBA-HYPE-INFO
    '187547',  # MBA-BI-INFO
    '187548',  # MBA-FCM-INFO
    '197606',  # OEBS Я.Инициатор_new
]
if is_groups(role, group=oebs_linked_groups, role='member'):
    if parent and parent.system and parent.system.slug in trusted_systems:
        approvers = []
        no_email = True
    else:
        raise AccessDenied('Данная роль является связанной и выдаётся только автоматически')

# членство в группе kuka дает доступ к куке релевантности
if is_groups(role, group='41130', role='member'):
    ad_groups = [','.join([
        'CN=kuka',
        'OU=search-viewers',
        'OU=Projects',
        'OU=Groups',
        'DC=ld',
        'DC=yandex',
        'DC=ru',
    ])]

    if is_personal_wf and user.works_in_dep('yandex_search_tech_sq'):
        approvers = []

# членство в группе SalesRes_AnalyticalReports_Writers добавляет в AD-группу
if is_groups(role, group='87160', role='member'):
    ad_groups = [','.join([
        'CN=Sales.Analytical_Reports.Resources.Writers',
        'OU=Sales.Resources',
        'OU=Resources',
        'OU=Projects',
        'OU=Groups',
        'DC=ld',
        'DC=yandex',
        'DC=ru',
    ])]

# членство в группе Zoo_AD добавляет в AD-группу
if is_groups(role, group='97598', role='member'):
    ad_groups = [','.join([
        'CN=ZOO4_Virtuals',
        'OU=ServerAccess',
        'OU=Projects',
        'OU=Groups',
        'DC=ld',
        'DC=yandex',
        'DC=ru',
    ])]

if is_groups(role, group=['42855', '42856']):
    approvers = any_from(['ivanmorozov', 'svshevtsov', 'iddqd'], priority=1)

if is_groups(role, group='115197', role='member'):
    if is_personal_wf and user.username == 'imperator':
        approvers = approver('tokza', priority=1)
    else:
        approvers = any_from(security_team())

if is_groups(role, group=['169790']):
    raise AccessDenied(
        'Выдача роли временно приостановлена в связи с необходимостью доработки с целью повышения уровня безопасности доступа к персональным данным сотрудников Яндекс. Тикет на доработку: STAFF-14023')

# не отправлять письма участникам группы Regional fridays
if is_groups(role, group='42375', role='member'):
    no_email = True

# подтверждающие для группы Сотрудники с доступом к реестру изменений
if is_groups(role, group='145232', role=['member', 'responsible']):
    approvers = any_from(['alleb', 'evgpopkova'])

# подтверждающие всегда Тигран или Даниил
if is_groups(role, group='79597', role=['member', 'responsible']):
    approvers = any_from(['tigran', 'daniilsh'])

# TOOLSUP-26701 сапорты выдают роли в группах без подтверждений
if is_groups(role) and approvers is None and requester in groupify(37188).get_descendant_members():
    approvers = []

# Если дошли сюда и согласующих нет, то согласуем мы
if approvers is None:
    approvers = staff_products

# Роли могут отрывать не только согласующие этой роли.
if request_type == REQUEST_TYPE.DEPRIVE:
    if not isinstance(approvers, list):
        approvers = [approvers]

    approvers.extend(staff_products)
    if is_personal_wf:
        approvers.append(user)
        approvers.extend(user.get_chain_of_heads())
    if original_requester:
        approvers.append(original_requester)

if (
    is_groups(role, group=['237039', '241560'], role='member')
    or is_department_roles(role, role='A')
    or is_department_roles(role, role='MA')
):
    ref_roles = [{
        'system': 'staff',
        'role_data': {'type': 'user_attrs', 'user_attr': 'is_staff'},
    }]
