import sform

from functools import partial
from itertools import chain

from intranet.femida.src.vacancies.choices import VACANCY_ROLES


_role_field_classes = {}


class VacancyRoleFieldMixin:
    """
    Миксин даёт возможность получать state поля
    в зависимости от роли пользователя в рамках конкретной вакансии.
    Для всех пользователей с ролью "рекрутер", а также для пользователей,
    которые имеют заданные роли на вакансии, отдаётся state указанный по умолчанию.
    Для всех остальных – read-only
    """
    def __init__(self, *, roles, **kwargs):
        super().__init__(**kwargs)
        self._roles = roles

    def get_state(self, vacancy, user):
        if user.is_recruiter:
            return self.state
        members = set(chain.from_iterable(vacancy.members_by_role[r] for r in self._roles))
        if user in members:
            return self.state
        return sform.READONLY


def _make_role_field_class(field_class):
    """
    Создаёт подкласс для миксина VacancyRoleFieldMixin и класса `field_class`.
    По сути, подмешивает логику миксина к заданному классу.
    """
    if field_class not in _role_field_classes:
        name = field_class.__name__
        parent_classes = (VacancyRoleFieldMixin, field_class)
        _role_field_classes[field_class] = type(name, parent_classes, {})
    return _role_field_classes[field_class]


def _make_role_field(field_class, roles, **kwargs):
    klass = _make_role_field_class(field_class)
    return klass(roles=roles, **kwargs)


def is_role_field(field):
    return isinstance(field, VacancyRoleFieldMixin)


# Note: это обёртки над полями редактирования вакансии.
# Чем выше уровень твоей роли на вакансии, тем больше у тебя возможностей.
# Соответственно, руководитель может менять всё, что могут НМ и ответственные за вак-ю,
# а НМ может всё, что могут отв-ные
HeadLevelField = partial(_make_role_field, roles=[VACANCY_ROLES.head])
HiringManagerLevelField = partial(_make_role_field, roles=[
    VACANCY_ROLES.head,
    VACANCY_ROLES.hiring_manager,
])
ResponsibleLevelField = partial(_make_role_field, roles=[
    VACANCY_ROLES.head,
    VACANCY_ROLES.hiring_manager,
    VACANCY_ROLES.responsible,
])
