import logging

from intranet.search.core.sources.directory.base import SourceBase
from intranet.search.core.sources.directory.client import join_fields, GROUP_GENERIC_TYPE
from intranet.search.core.sources.utils import (
    get_by_lang,
    get_document_url,
    get_person_name_by_lang,
    hash_factor,
    timestamp_to_utc_date,
)
from intranet.search.core.sources.people import utils
from intranet.search.core.snippets.directory import UserSnippet

log = logging.getLogger(__name__)


class Source(SourceBase):
    """ Индексатор пользователей директории
    """
    doc_type = 'user'

    _user_fields = (
        'id',
        'nickname',
        'name',
        'email',
        'contacts',
        'position',
        'gender',
        'about',
        'is_dismissed',
        'birthday',
        'department',
        'groups',
        'aliases',
        'cloud_uid',
    )
    _department_fields = (
        'id',
        'name',
        'label',
        'email',
        'description',
    )
    _group_fields = (
        'id',
        'name',
        'label',
        'type',
        'email',
        'description',
    )

    FIELDS = join_fields((
        join_fields(_user_fields),
        join_fields(_department_fields, prefix='department'),
        join_fields(_group_fields, prefix='groups'),
    ))

    def _get_directory_filter(self, keys):
        """ Формирует фильтры на основе переданных keys.
        :param keys: список ключей для фильтрации.
        Ключи имеют определенный формат.
            - департамент - "department:<id>"
            - группа - "group:<id>"
            - логин - просто логин пользователя
        """
        if not keys:
            return {}

        department_filter = []
        group_filter = []
        login_filter = []

        department_pattern = 'department:'
        group_pattern = 'group:'

        for key in keys:
            if key.startswith(department_pattern):
                department_filter.append(key[len(department_pattern):])
            elif key.startswith(group_pattern):
                group_filter.append(key[len(group_pattern):])
            else:
                login_filter.append(key)

        filters = {}
        if login_filter:
            filters['nickname'] = ','.join(login_filter)
        if department_filter:
            filters['department_id'] = ','.join(department_filter)
        if group_filter:
            filters['group_id'] = ','.join(group_filter)
        return filters

    def _request_directory(self, page=1):
        params = {'page': page, 'fields': self.FIELDS}
        if self.options['ts']:
            date = timestamp_to_utc_date(self.options['ts'])
            params['created__gt'] = date.isoformat()
        params.update(self._get_directory_filter(self.options['keys']))
        return self.api_client.get_users(self.org_directory_id, **params)

    def do_create(self, obj, **kwargs):
        # оставляем для индексации только generic группы
        obj['groups'] = [g for g in obj.get('groups', []) if g['type'] == GROUP_GENERIC_TYPE]
        super().do_create(obj, **kwargs)

    def fetch_object(self, obj_id):
        return self.api_client.get_user(obj_id, self.org_directory_id, fields=self.FIELDS)

    def create_body(self, obj, **kwargs):
        contacts = {}
        for contact in obj['contacts']:
            c_type = contact['type']
            if c_type not in contacts:
                contacts[c_type] = list(utils.get_contact_type_forms(c_type))
            contacts[c_type].extend(self._get_contacts_forms(contact))

        body = {
            'id': obj['id'],
            'cloud_uid': obj['cloud_uid'],
            'login': obj['nickname'],
            'position': obj['position'],
            'name': obj['name'],
            'personal': {
                'gender': utils.get_gender_forms(obj['gender']),
            },
            'contacts': contacts,
            'groups': []
        }

        if obj.get('department'):
            body['department'] = {
                'department_label': obj['department']['label'],
                'department_name': obj['department']['name'],
                'department_description': obj['department']['description'],
            }

        for group in obj.get('groups', []):
            group_data = [group['label']]
            for lang in self.snippet_languages:
                group_data.extend(
                    str(get_by_lang(group[field], lang))
                    for field in ('name', 'description')
                    if group[field]
                )
            body['groups'].append(' '.join(s for s in group_data if s))

        return body

    def create_snippet(self, obj, lang='ru', **kwargs):
        data = {
            'uid': obj['id'],
            'cloud_uid': obj['cloud_uid'],
            'login': obj['nickname'],
            'name': get_person_name_by_lang(obj, lang),
            'work_email': obj['email'],
            'url': get_document_url('users').format(login=obj['nickname']),
            'doc_type': self.doc_type,
        }

        for field in ('is_dismissed', 'gender', 'birthday'):
            data[field] = obj[field]

        for field in ('position', 'about'):
            data[field] = get_by_lang(obj[field], field)

        data['contacts'], data['phones'] = self.dump_contacts(obj, lang)

        if obj.get('department'):
            data['department'] = self.dump_department(obj['department'], lang)

        data['groups'] = []
        for group in obj.get('groups', []):
            group_data = self.dump_group(group, lang)
            group_data['type'] = group['type']
            data['groups'].append(group_data)

        return UserSnippet(data)

    def _get_contacts_forms(self, contact):
        if contact['type'] == 'phone':
            return list(utils.gen_phones(contact['value']))
        return [contact['value']]

    def dump_department(self, data, lang):
        dump = {
            'id': data['id'],
            'url': data['label'],
            'label': data['label'],
            'dep_name': get_by_lang(data['name'], lang),
            'description': get_by_lang(data['description'], lang),
            'maillists': [data['email']] if data['email'] else []
        }
        return dump

    def dump_group(self, data, lang):
        dump = {
            'name': get_by_lang(data['name'], lang),
            'description': get_by_lang(data['description'], lang)
        }
        for field in ('id', 'label', 'email'):
            dump[field] = data[field]
        return dump

    def dump_contacts(self, obj, lang):
        contacts = []
        phones = []
        for c in obj.get('contacts', []):
            if not c['value']:
                continue

            dump = {
                'type': c['type'],
                'value': c['value'],
                '_type_forms': utils.get_contact_type_forms(c['type']),
            }
            if c['type'] == 'phone':
                dump['_forms'] = self._get_contacts_forms(c)
                dump['description'] = get_by_lang(utils.contact_labels[c['type']], lang)
                phones.append(dump)
            else:
                dump['label'] = get_by_lang(utils.contact_labels.get(c['type']), lang) or c['type']
                contacts.append(dump)
        return contacts, phones

    def emit_factors(self, doc, obj):
        if obj['is_dismissed']:
            doc.emit_factor('isFormer', 1)
        doc.emit_factor('urlHash', hash_factor(doc.url))

    def emit_attrs(self, doc, obj):
        if obj.get('department'):
            doc.emit_facet_attr('department', obj['department']['id'],
                                get_by_lang(obj['department']['name'], 'ru'),
                                get_by_lang(obj['department']['name'], 'en'))
        else:
            doc.emit_facet_attr('department', 0, 'Без департамента', 'No department')

        if obj.get('groups'):
            for group in obj['groups']:
                doc.emit_facet_attr('group', group['id'],
                                    get_by_lang(group['name'], 'ru'),
                                    get_by_lang(group['name'], 'en'))
        else:
            doc.emit_facet_attr('group', 0, 'Без группы', 'No group')

        doc.emit_suggest_attr(obj['nickname'])
        for field in ('first', 'last'):
            doc.emit_suggest_attr(obj['name'].get(field))
        for alias in obj['aliases'] or []:
            doc.emit_suggest_attr(alias)
