from intranet.search.core.sources.plan.base import BaseSource
from intranet.search.core.sources.utils import get_text_content, get_by_lang
from intranet.search.core.sources.plan.utils import normalize_url, contact_types, SERVICE_STATE_MAP
from intranet.search.core.utils import get_ids_repository


class Source(BaseSource):
    """
    Индексатор сервисов
    """
    service_members_repo = get_ids_repository('abc', 'service_members', api_version=4, timeout=5)

    SERVICE_FIELDS = BaseSource.SERVICE_FIELDS + [
        'keywords',
        'owner',
    ]

    def fetch_object(self, obj):
        obj = super().fetch_object(obj)
        obj['members'] = set()
        for member in self.service_members_repo.getiter({'service': obj['id']}):
            obj['members'].add(member['person']['id'])

        return obj

    def create_body(self, obj, **kwargs):
        contacts = self.get_contacts_for_index(obj.get('contacts', []))
        body = {
            'service_description': {
                'description': get_text_content(obj['description']['ru']),
                'description_en': get_text_content(obj['description']['en']),
            },
            'z_ns_hidden': {
                'service_slug': obj['slug'],
                'service_full_name': {
                    'name': obj['name']['ru'],
                    'name_en': obj['name']['en'],
                    'id': obj['id'],
                },
                'service_search': {
                    'service_keywords': obj.get('keywords'),
                    'service_contacts': contacts,
                },
            },
        }
        return body

    def create_snippet(self, obj, lang='ru', **kwargs):
        if obj.get('owner'):
            owner = {
                'login': obj['owner']['login'],
                'first_name': get_by_lang(obj['owner']['first_name'], lang),
                'last_name': get_by_lang(obj['owner']['last_name'], lang),
            }
        else:
            owner = None

        description = get_text_content(get_by_lang(obj['description'], lang))

        return {
            'id': obj['id'],
            'name': get_by_lang(obj['name'], lang),
            'description': description,
            'slug': obj['slug'],
            'contacts': self.get_contacts_for_snippet(obj.get('contacts', []), lang),
            'status': obj['state'],
            'team_size': obj['unique_immediate_members_count'],
            'person': owner,
        }

    def emit_factors(self, doc, obj):
        super().emit_factors(doc, obj)
        doc.emit_meta_factor('isServices', 1)

    def emit_attrs(self, doc, obj):
        doc.emit_search_attr('public', '1')
        doc.emit_search_attr('is_empty', '0')
        doc.emit_search_attr('s_slug', obj['slug'])
        doc.emit_search_attr('s_name', obj['name']['ru'])
        doc.emit_search_attr('s_name_en', obj['name']['en'])
        doc.emit_search_attr('i_is_closed', int(obj.get('state') == 'closed'))
        if obj.get('owner'):
            doc.emit_facet_attr(
                name='owner',
                value=obj['owner']['login'],
                label=get_by_lang(obj['owner']['name'], 'ru'),
                label_en=get_by_lang(obj['owner']['name'], 'en'),
            )

        doc.emit_facet_attr(
            name='status',
            value=obj['state'],
            label=SERVICE_STATE_MAP[obj['state']]['ru'],
            label_en=obj['state'],
        )

        for tag in obj['tags']:
            doc.emit_search_attr('s_tag', tag['slug'])

        for member in obj['members']:
            doc.emit_group_attr('member', member)

    def get_contacts_for_index(self, contacts):
        result = []

        # Основные типы контактов для индекса.
        # Эти типы хорошо подходят, потому что содержат только slug,
        # без сложных путей, которые могут содержать нерелевантную инфу.
        # Исключение – url_sitelink
        contact_types_for_index = {
            'url_at_club',
            'email_ml',
            'tracker_startrek',
            'url_sitelink',
        }

        for contact in contacts:
            if contact['content'] and contact['type']['code'] in contact_types_for_index:
                result.append(contact['content'])

        return result

    def get_contacts_for_snippet(self, contacts, lang):
        """
        Отдаёт по одному контакту каждого типа в заданном порядке
        """
        order = {v: k for k, v in enumerate(contact_types)}
        result = []
        used_types = set()

        for contact in sorted(contacts, key=lambda x: order.get(x['type']['code'], len(order))):
            if not contact['title'] and not contact['content']:
                continue
            if contact['type']['code'] not in used_types:
                result.append(self.normalize_contact(contact, lang))
                used_types.add(contact['type']['code'])

        return result

    def normalize_contact(self, contact, lang):
        title = self.normalize_title(contact, lang)

        content = contact['content']
        contact_type = contact['type']['code'] or ''

        if contact_types.get(contact_type, {}).get('url'):
            content = normalize_url(content, contact_type)

        return {'title': title, 'content': content, 'type': contact_type}

    def normalize_title(self, contact, lang):
        title = get_by_lang(contact['title'], lang).strip()
        defaults = contact_types.get(contact['type']['code'], {})
        contact_title = get_by_lang(defaults.get('title'), lang)

        if contact_title:
            title = contact_title
        else:
            if not title:
                title = get_by_lang(defaults.get('default_title'), lang)
            if 'tracker' in contact['type']['code']:
                title = contact['content'].upper()
        return title
