#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
import yaml
import logging

from saas.library.python.token_store import PersistentTokenStore
from saas.library.python.token_store.errors import PersistentTokenStoreError


def read_configuration(config_file):
    """
    Read configuration file in yaml format
    """
    try:
        with open(config_file) as cf:
            config = yaml.load("".join(cf.readlines()))
        return config
    except EnvironmentError:
        logging.critical('Cannot open/parse config file: %s', config_file)
        exit(1)


class ABCApi(object):
    """
    Main class for ABC api requests.
    """

    API_URL = 'https://abc-back.yandex-team.ru/api/v4/'
    SERVICE_FIELDS = ['id', 'name', 'slug', 'parent', 'path']

    def __init__(self):
        try:
            oauth_token = PersistentTokenStore.get_token_from_store_env_or_file('abc')
        except PersistentTokenStoreError:
            logging.error('ABC_TOKEN was not found in environment. Correct work will not be guaranteed.')
            oauth_token = ''

        self.__connection = requests.session()
        self.__connection.headers = {'Authorization': 'OAuth %s' % oauth_token}

    def _get_service_info(self, service_id):
        """
        Get information about service.
        :param service_id: type str
        :return: type dict
        """
        resp = self.__connection.get('%s/services/%s/?fields=%s' % (self.API_URL, service_id, ','.join(self.SERVICE_FIELDS)))
        return resp.json()

    def _get_service_duty(self, service_id):
        """
        Get service duty.
        :param service_id: type str
        :return: type dict
        """
        resp = self.__connection.get('%s/services/%s/on_duty/' % (self.API_URL, service_id))
        return resp.json()

    def _get_service_info_by_slug(self, service_slug):
        """
        Get information about service by slug.
        :param service_slug: type str
        :return: type dict
        """
        resp = self.__connection.get('%s/services/?slug=%s&fields=%s' % (self.API_URL, service_slug, ','.join(self.SERVICE_FIELDS)))
        return resp.json()

    def _get_service_members(self, service_id, role=None):
        """
        Get information about service members
        :param service_id: type str
        :return: type list of dict
        """
        request_url = '%s/services/members/?service=%s' % (self.API_URL, service_id)
        if role:
            request_url += '&role__scope=%s' % role
        resp = self.__connection.get(request_url).json()
        return resp['results']

    def _get_person_from_service(self, service_id, login):
        """
        Get information about user in ABC service
        :param service_id: type str
        :param login: type str
        :return: type dict
        """
        request_url = '%s/services/members/?service=%s&person=%s' % (self.API_URL, service_id, login)
        resp = self.__connection.get(request_url)
        return resp.json()

    def _get_services_by_person(self, login):
        """
        Get information about user roles in services
        :param service_id: type str
        :param login: type str
        :return: type dict
        """
        request_url = '%s/services/members/?person__login=%s' % (self.API_URL, login)
        resp = self.__connection.get(request_url)
        return resp.json()

    @staticmethod
    def _collect_logins_by_role(team_data, role):
        """
        Collect list of logins accodring by specified service role.
        :param team_data: type dict
        :param role: type str
        :return: type list
        """
        login_list = []
        for employee in team_data:
            if role in employee['role']['scope']['slug']:
                login = employee['person']['login']
                if login not in login_list:
                    login_list.append(login)
        return login_list

    def get_logins_by_role(self, service, role):
        """
        Main func for collect employees with specified role in specified service.
        :param service: type str
        :param role: type str
        :return: type list
        """
        logins_data = self._get_service_members(service, role)
        return self._collect_logins_by_role(logins_data, role)

    def get_hr_service_name(self, service, lang='ru'):
        """
        Method for get human-readable service name
        :param service: type str
        :param lang: type str in ['ru', 'en']
        :return: type str, type str
        """
        service_info = self._get_service_info(service)
        return service_info.get('slug'), service_info.get('name', {}).get(lang)

    def get_service_id(self, service):
        """
        Method for get abc id service by service slug
        :param service: type str
        :return: return type str
        """
        service_info = self._get_service_info_by_slug(service)
        return service_info['results'][0].get('id')

    def get_current_duty(self, service):
        """
        Metroh for get current duty for SaaS/
        :param service: type str
        :return: type str
        """
        if type(service) is str and not service.isdigit():
            service = self.get_service_id(service)
        duty_info = self._get_service_duty(service)
        return duty_info[0]['person']['login']

    def check_user_in_service(self, service, user_login):
        """
        Check for user presented in service
        :param service: type str
        :param user_login: type str
        :return: type bool
        """
        user_data = self._get_person_from_service(service, user_login)
        if user_data['results']:
            return True
        return False

    def check_service_parent(self, service_child_id, service_parent_id):
        """
        Check for service child in service parent by path
        :param service_child_id: type str
        :param service_parent_id: type str
        :return: type boolean
        """
        service_child = self._get_service_info(service_child_id)
        service_parent = self._get_service_info(service_parent_id).get('slug')
        if service_parent in service_child['path'].split('/'):
            return True
        return False

    def check_user_in_staff(self, login):
        """
        Check user in staff py handle /services/members for roles. No roles == user is not present.
        :param login: type str
        :return: type boolean
        """
        user_service_roles = self._get_services_by_person(login)
        if len(user_service_roles.get('results', 0)) == 0:
            return False
        else:
            return True
