from typing import Any, AnyStr, Dict, List, Set

from staff.lib.utils.qs_values import localize
from staff.person_profile.cards.blocks import (
    AbstractBlock,
    CardBaseFieldsBlock,
    CardNamesBlock,
    CardPhonesBlock,
    CardPersonalBlock,
    CardLocationOfficeBlock,
    CardLocationTableBlock,
    CardDepartmentFieldsBlock,
    CardLastOfficeBlock,
    CardGapBlock,
    CardPositionBlock,
    CardAccountsBlock,
    CardAvatarFieldsBlock,
    CardLocationRoomBlock,
)
from staff.person_profile.permissions.base import BaseRegistry


class CardsMetaBlocksRegistry(object):
    default_data = {
        'first_name': '',
        'last_name': '',
    }

    def __init__(self, data, registry):  # type: (dict, BaseRegistry) -> None
        self.registry = registry
        self.data = localize(data)
        self._inited_blocks = self._get_inited_blocks()

    @classmethod
    def get_all_blocks(cls):  # type: () -> List[type]
        return [
            CardBaseFieldsBlock,
            CardNamesBlock,
            CardPhonesBlock,
            CardPersonalBlock,
            CardLocationOfficeBlock,
            CardLocationRoomBlock,
            CardLocationTableBlock,
            CardDepartmentFieldsBlock,
            CardLastOfficeBlock,
            CardGapBlock,
            CardPositionBlock,
            CardAccountsBlock,
            CardAvatarFieldsBlock,
        ]

    @classmethod
    def get_fields(cls):  # type: () -> Set[str]
        fields = set()
        for block in cls.get_all_blocks():
            fields |= block.fields
        return fields

    def _get_available_blocks(self):  # type: () -> List[type]
        return [
            b
            for b in self.get_all_blocks()
            if b.name is None
            or b.name
            and self.registry.is_available(b.name, target_login=self.data['login'])
        ]

    def _get_inited_blocks(self):  # type: () -> List[AbstractBlock]
        cache = {}
        return [b(self.data, cache) for b in self._get_available_blocks()]

    def get_data(self):  # type: () -> Dict[AnyStr, Any]
        result = self.default_data.copy()
        for block in self._inited_blocks:
            result.update(block.get_data())
        return result
