# -*- coding: utf-8 -*-
#
# Copyright (C) 2014-2016 Avencall
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>

import logging
from json import dumps

from xivo_confd_client import Client

from xivo_dird import BaseSourcePlugin
from xivo_dird import make_result_class

logger = logging.getLogger(__name__)


class XivoUserPlugin(BaseSourcePlugin):
    _valid_keys = ['id', 'exten', 'firstname', 'lastname', 'userfield', 'email',
                   'description', 'mobile_phone_number', 'voicemail_number']

    def __init__(self, confd_client_class=Client):
        self._ConfdClientClass = confd_client_class
        self._client = None
        self._uuid = None
        self._search_params = {'view': 'directory'}

    def load(self, args):
        self._searched_columns = args['config'].get(self.SEARCHED_COLUMNS, [])
        self._first_matched_columns = args['config'].get(self.FIRST_MATCHED_COLUMNS, [])
        self.name = args['config']['name']

        confd_config = args['config']['confd_config']
        logger.debug('confd config %s', confd_config)
        self._client = self._ConfdClientClass(**confd_config)

        self._source_result = make_result_class(
            self.name, 'id',
            format_columns=args['config'].get(self.FORMAT_COLUMNS))

        self._search_params.update(args['config'].get('extra_search_params', {}))

        logger.info('XiVO %s successfully loaded', args['config']['name'])

    def name(self):
        return self.name

    def search(self, term, profile=None, args=None):
        return self._fetch_entries(term=term, search_columns=self._searched_columns)

    def first_match(self, term, args=None):
        logger.debug(f"Reverse lookup - Search for term {term} with args {args}, searching in {self._first_matched_columns}")
        entries = self._fetch_entries(term=term, search_columns=self._first_matched_columns, search_type='search')
        logger.debug(f"Reverse lookup - Entries found {entries}")
        
        def match_fn(entry):
            for column in self._first_matched_columns:
                logger.debug(f"Reverse lookup - Searching in column {column} for entry {entry}")
                if term == entry.fields.get(column):
                    return True
            return False

        for entry in entries:
            if match_fn(entry):
                return entry
        return None

    def list(self, unique_ids, args=None):
        if len(unique_ids) == 0:
            return list()
        return list(self._fetch_entries(unique_ids=dumps(unique_ids)))

    def _fetch_entries(self, **kwargs):
        try:
            uuid = self._get_uuid()
        except Exception:
            logger.exception('Cannot fetch UUID. No results will be returned')
            return []

        try:
            entries = self._fetch_users(**kwargs)
        except Exception:
            logger.exception('Cannot fetch entries. No results will be returned')
            return []

        return list(self._source_result_from_entry(entry, uuid) for entry in entries)

    def _get_uuid(self):
        if self._uuid:
            return self._uuid

        self._uuid = self._client.infos()['uuid']
        return self._uuid

    def _fetch_users(self, search_type='search_ng', **kwargs):
        term = kwargs.pop('term', None) or ''
        search_params = dict(self._search_params)
        search_params[search_type] = term
        search_params.update(kwargs)
        return self._client.users.list(**search_params)['items']

    def _source_result_from_entry(self, entry, uuid):
        return self._source_result({key: entry.get(key) for key in self._valid_keys},
                                   xivo_id=uuid,
                                   agent_id=entry['agent_id'],
                                   user_id=entry['id'],
                                   user_uuid=entry['uuid'],
                                   endpoint_id=entry['line_id'])
