from django.views.decorators.http import require_http_methods

from staff.lib import query
from staff.lib.decorators import responding_json, paginated, use_request_lang
from staff.lib.utils.qs_values import extract_related
from staff.person.models import Staff

from staff.person_profile.controllers.blocks.abstract_dep_chain_block import get_roles_data
from staff.person_profile.controllers.blocks.birthday_block import BirthdayBlock
from staff.person_profile.controllers.blocks.chief_block import ChiefBlock
from staff.person_profile.controllers.blocks.dismissed_block import DismissedBlock
from staff.person_profile.controllers.blocks.hr_partner_block import HRPartnerBlock
from staff.person_profile.controllers.blocks.location_office_block import LocationOfficeBlock
from staff.person_profile.controllers.blocks.location_room_block import LocationRoomBlock
from staff.person_profile.controllers.blocks.location_table_block import LocationTableBlock
from staff.person_profile.controllers.blocks.official_organization_block import OfficialOrganizationBlock
from staff.person_profile.controllers.blocks.paid_day_off_block import PaidDayOffBlock
from staff.person_profile.controllers.blocks.password_block import PasswordBlock
from staff.person_profile.controllers.blocks.personal_block import PersonalBlock
from staff.person_profile.controllers.blocks.umbrellas_block import UmbrellasBlock, get_person_umbrellas
from staff.person_profile.controllers.blocks.vacation_block import VacationBlock
from staff.person_profile.controllers.blocks.value_stream_block import (
    ValueStreamBlock,
    get_persons_value_streams,
    get_value_stream_data,
)
from staff.person_profile.controllers.blocks.work_mode_block import WorkModeBlock
from staff.person_profile.permissions.utils import get_block_registry


REQUIRED_FIELDS = (
    'id',
    'login',
)

PERMISSION_FIELDS = (
    'edit_umbrellas',
)


# Имена допустимых полей — атрибуты BlockRegistry
# (там проверяется доступ к полям).
# В блоках есть информация о полях в базе и
# бизнес-логика по формированию данных для поля
FIELDS_BLOCKS = {
    'birthday': BirthdayBlock,
    'chief': ChiefBlock,
    'hr_partners': HRPartnerBlock,
    'location_office': LocationOfficeBlock,
    'location_room': LocationRoomBlock,
    'location_table': LocationTableBlock,
    'official_organization': OfficialOrganizationBlock,
    'paid_day_off': PaidDayOffBlock,
    'password': PasswordBlock,
    'personal': PersonalBlock,
    'quit_at': DismissedBlock,
    'umbrellas': UmbrellasBlock,
    'vacation': VacationBlock,
    'value_streams': ValueStreamBlock,
    'work_mode': WorkModeBlock,
}


def filter_allowed_fields(requested_fields):
    all_fields = FIELDS_BLOCKS.keys()

    allowed = set(all_fields)
    if 'all' not in requested_fields:
        allowed &= set(requested_fields)

    allowed |= set(REQUIRED_FIELDS)
    allowed |= set(PERMISSION_FIELDS)
    return allowed


def get_db_fields(requested_fields):
    result = set()
    for field in requested_fields:
        if field in REQUIRED_FIELDS:
            result.add(field)
        elif field in PERMISSION_FIELDS:
            pass
        else:
            result |= FIELDS_BLOCKS[field].fields
    return result


def get_field_value(field, person, cache):
    block = FIELDS_BLOCKS[field](data=person, cache=cache)
    block_data = block.get_data()
    if isinstance(block_data, dict) and set(block_data) == {field}:
        return block_data[field]
    return block_data


@require_http_methods(['GET', 'POST'])
@responding_json
@use_request_lang
@paginated
def get_bulk(request, paginator):
    logins = query.get_list_request_param(request, name='logins')
    fields = query.get_list_request_param(request, name='fields')
    fields = filter_allowed_fields(fields)

    db_fields = get_db_fields(requested_fields=fields)
    persons = Staff.objects.filter(login__in=logins).values(*db_fields)
    paginator.update_by_queryset(queryset=persons)

    block_registry = get_block_registry(
        observer=request.user.get_profile(),
        login_or_logins=logins,
        service_readonly=request.service_is_readonly,
    )

    person_value_stream_data = get_persons_value_streams(logins)
    vs_data_list = [vs_data for vs_data in person_value_stream_data.values() if vs_data]
    dep_data_list = [extract_related(person, 'department', pop=False) for person in paginator.result]

    cache = {
        # TODO: Put 'department_chain' to cache
        'roles_chain': get_roles_data(department_list=dep_data_list + vs_data_list),
        'person_value_stream_data': person_value_stream_data,
        # TODO: Put vs chain to cache
        'value_stream_data': get_value_stream_data({x['url'] for x in vs_data_list}),
        'person_umbrellas': get_person_umbrellas(logins),
    }

    for index, person in enumerate(paginator.result):
        data = {}
        login = person['login']

        for field in fields:
            if field in REQUIRED_FIELDS:
                data[field] = person[field]
                continue

            if not block_registry.is_available(attr=field, target_login=login):
                continue

            if field in PERMISSION_FIELDS:
                data.setdefault('permissions', []).append(field)
                continue
            else:
                data[field] = get_field_value(field, person, cache)

        paginator.result[index] = data

    return paginator
