import logging
from collections import defaultdict
from datetime import datetime

from django.conf import settings
from tornado import gen

from intranet.search.abovemeta.request import Request
from intranet.search.abovemeta.steps.base import (
    timeouts,
    CachedHttpStep,
    HttpStep,
    FoundDocsConditionalHttpStepMixin,
)

log = logging.getLogger(__name__)


GROUPS_LIMIT = 300  # максимальное количество групп, которое мы будем учитывать в acl
# группа внешних сотрудников с полным доступом к Staff
EXT_WITH_FULL_STAFF_ACCESS_GROUP_URL = 'ext_with_full_staff_access'


class BaseStaffStep(CachedHttpStep):
    """
    Базовый step для запросов в staff-api/persons
    """
    name = None
    fields = ()

    def get_cache_key(self, state):
        return f'{self.name}:{state.user}'

    def get_request(self, state):
        endpoint = settings.ISEARCH['api']['staff']['persons']
        query = {
            'login': state.user,
            '_fields': ','.join(self.fields),
            '_one': 1,
        }
        return Request(
            url=endpoint.url(query=query),
            type_='staff',
            name=self.name,
            headers=endpoint.headers(),
            request_timeout=timeouts[self.name],
            retries=1,
        )


class GroupsStep(BaseStaffStep):
    name = 'groups'
    fields = (
        'id',
        'language.auto_translate',
        'groups.group.id',
        'groups.group.url',
        'groups.group.type',
        'groups.group.ancestors.id',
        'groups.group.ancestors.url',
        'location.office.id',
        'location.table.floor.id',
        'official.affiliation',
    )

    def get_future(self, state, requester):
        if state.auth_method == 'tvm_werewolf':
            werewolf_result = {
                'id': settings.TVM2_WEREWOLFING_STAFF_ID,
                'groups': settings.TVM2_WEREWOLFING_GROUPS,
                'location': {
                    'office': {
                        'id': settings.TVM2_WEREWOLFING_USER_OFFICE,
                    },
                    'table': {
                        'floor': {
                            'id': settings.TVM2_WEREWOLFING_USER_FLOOR
                        }
                    },
                },
                'official': {
                    'affiliation': 'yandex'
                },
                'language': {
                    'auto_translate': False,
                }
            }
            future = gen.Future()
            future.set_result(werewolf_result)
            return future
        return super().get_future(state, requester)

    def set_data(self, state, data):
        departments = set()
        parent_departments = set()
        services = set()
        groups_set = set()
        user_is_ext_with_full_staff_access = False

        for grp in data.get('groups', []):
            group = grp['group']
            group_type = group.get('type')
            groups_set.add(group['id'])
            groups_set.update({anc['id'] for anc in group.get('ancestors', [])})

            if group_type == 'service':
                services.add(group['id'])
            elif group_type == 'department':
                departments.add(group['id'])
                if group.get('ancestors'):
                    # берём только одного ближайшего родителя
                    parent_departments.add(group['ancestors'][-1]['id'])
            if group.get('url') == EXT_WITH_FULL_STAFF_ACCESS_GROUP_URL:
                user_is_ext_with_full_staff_access = True

        state.staff_id = data['id']
        state.groups = sorted(groups_set)[:GROUPS_LIMIT]

        state.user_departments = sorted(departments)
        state.user_parent_departments = sorted(parent_departments)
        state.user_services = sorted(services)

        state.user_base_office = data['location']['office'].get('id')
        state.user_base_floor = data['location']['table']['floor'].get('id')
        state.auto_translate = data['language'].get('auto_translate', False)

        state.user_has_full_staff_access = (
            data['official']['affiliation'] in ('yandex', 'yamoney')
            or user_is_ext_with_full_staff_access
        )

    def set_error(self, state, response):
        state.groups = [settings.ISEARCH_MAIN_STAFF_GROUP]


class GapStep(FoundDocsConditionalHttpStepMixin, HttpStep):
    search = 'people'
    index = ''

    def need_to_do_step(self, state, docs):
        return state.feature_enabled('get_user_gaps') and docs

    def get_logins(self, docs):
        login_list = []
        for doc in docs:
            login = doc.raw_snippet.get('login')
            if login:
                login_list.append(login)
        return login_list

    def get_request(self, state, docs):
        endpoint = settings.ISEARCH['api']['gap']
        now = datetime.utcnow().isoformat()

        query = {
            'person_login': self.get_logins(docs),
            'date_from': now,
            'date_to': now,
        }
        return Request(
            url=endpoint.url(query=query),
            type_='staff',
            name='gap',
            headers=endpoint.headers(),
            request_timeout=timeouts['gap'],
            retries=1,
        )

    def set_data(self, state, response):
        gaps_dict = defaultdict(list)
        for gap in response.get('gaps', []):
            gap_data = {
                'type': gap['workflow'],
                'work_in_absence': gap['work_in_absence'],
                'date_from': gap['date_from'],
                'date_to': gap['date_to'],
            }
            gaps_dict[gap['person_login']].append(gap_data)

        for doc in self.get_found_docs(state):
            doc.raw_snippet['gaps'] = gaps_dict.get(doc.raw_snippet['login'], [])
