# coding: utf-8

from __future__ import unicode_literals

import yenv

import attr
from django import http
from django.conf import settings

from ids.connector.plugins_lib import PluginBase


class Auth(object):

    uid = None
    login = None
    password = None
    session_id = None
    session_id2 = None
    staff_id = None
    oauth_token = None
    ticket = None

    def __init__(self, **kwargs):
        self.person = Person(
            uid=kwargs.get('uid'),
            login=kwargs.get('login'),
            staff_id=kwargs.get('staff_id'),
        )
        self.password = kwargs.get('password')
        self.session_id = kwargs.get('session_id')
        self.session_id2 = kwargs.get('session_id2')
        self.oauth_token = kwargs.get('oauth_token')
        self.ticket = kwargs.get('ticket')

        # не очень мне нравится этот атрибут, но что-то должно быть
        self.extra = {}

    @property
    def uid(self):
        return self.person.uid

    @property
    def login(self):
        return self.person.login

    @property
    def staff_id(self):
        return self.person.staff_id

    @uid.setter
    def uid(self, value):
        self.person.uid = value

    @login.setter
    def login(self, value):
        self.person.login = value

    @staff_id.setter
    def staff_id(self, value):
        self.person.staff_id = value

    def __repr__(self):
        return "{class_name}(login='{login}', uid='{uid}')".format(
            class_name=self.__class__.__name__,
            login=self.login if self.login else '',
            uid=self.uid if self.uid else '',
        )


@attr.s
class Person(object):
    uid = attr.ib()
    login = attr.ib()
    staff_id = attr.ib()

    @property
    def id_dict(self):
        return {
            'uid': self.uid,
            'login': self.login,
            'staff_id': self.staff_id,
        }

    @classmethod
    def from_staff_api_data(cls, data):
        return cls(
            uid=data['uid'],
            login=data['login'],
            staff_id=data['id'],
        )


class MultiAuthPlugin(PluginBase):

    required_params = [
        'auth',
    ]

    def prepare_params(self, params):
        from cab.sources import oauth

        auth = self.connector.auth
        available_auth_types = self.connector.available_auth_types

        if auth.oauth_token and 'oauth' in available_auth_types:
            self.prepare_oauth_params(params, oauth_token=auth.oauth_token)

        elif 'debug-login' in available_auth_types:
            # only for cia services
            self.prepare_debug_login_params(params, login=auth.login)

        elif auth.session_id and 'session_id' in available_auth_types:
            self.prepare_session_id_params(params, session_id=auth.session_id)

        elif auth.login and auth.password:
            if 'oauth' in available_auth_types:
                oauth_token = oauth.get_token_by_password(
                    username=auth.login,
                    password=auth.password
                )
                self.prepare_oauth_params(params, oauth_token=oauth_token)

        elif auth.ticket and 'ticket' in available_auth_types:
            self.prepare_ticket_params(params, ticket=auth.ticket)

        # нерекомендуемый способ получения токена
        # работает только, если для всех скоупов, выбранных для приложения
        # включена спецнастройка, позволяющая получать токен таким образом
        # (фолбек на staff-robot)
        elif (
            'Authorization' not in params.get('headers', {}) and
            'oauth' in available_auth_types and
            hasattr(settings, 'DEFAULT_OAUTH_TOKEN')
        ):
            self.prepare_oauth_params(
                params,
                oauth_token=settings.DEFAULT_OAUTH_TOKEN,
            )


    def prepare_oauth_params(self, params, oauth_token):
        headers = params.get('headers', {})
        headers['Authorization'] = 'OAuth ' + oauth_token
        params['headers'] = headers

    def prepare_session_id_params(self, params, session_id):
        cookies = params.get('cookies', {})
        cookies['Session_id'] = session_id
        params['cookies'] = cookies

    def prepare_ticket_params(self, params, ticket):
        headers = params.get('headers', {})
        headers['Ticket'] = ticket
        params['headers'] = headers

    def prepare_debug_login_params(self, params, login):
        headers = params.get('headers', {})
        headers['DEBUG-LOGIN'] = login
        params['headers'] = headers


class AuthMiddleware(object):
    """
    Sets auth attribute for django request.
    TODO: move to ids
    """
    def process_request(self, request):
        self.set_auth_attribute(request=request)

    def set_auth_attribute(self, request):
        auth_header = request.META.get('Authorization')
        if '_oauth' in request.GET:
            oauth_token = request.GET['_oauth']
        else:
            oauth_token = auth_header and auth_header[len('OAuth '):]
        request.auth = Auth(
            session_id=request.COOKIES.get('Session_id'),
            session_id2=request.COOKIES.get('sessionid2'),
            oauth_token=oauth_token,
            login=request.yauser.login,
            uid=request.yauser.uid,
        )


class UserInfoMiddleware(object):

    def process_request(self, request):
        from cab.sources import staff_api

        auth = request.auth
        data = staff_api.get_person_data(login=auth.login)
        auth.staff_id = data['id']
        auth.extra['department_id'] = data['department_group']['department']['id']


class AccessMiddleware(object):

    def process_request(self, request):
        # Не делаем проверку для этой ручки, так как данные из неё
        # должны быть доступны на странице калькулятора займов /money/loan
        if request.path == '/api/widgets/person/':
            return None

        if self.is_in_forbidden_tree(request.auth):
            msg = settings.FORBIDDEN_SLUGS + ' departments forbidden'
            return http.HttpResponseForbidden(msg)

    @staticmethod
    def is_in_forbidden_tree(auth):
        """
        Доступ должен пропадать у сотрудников самого подразделения, чей
        url был указан, и у сотрудников дочерних.
        """
        from cab.sources import staff_api

        if not settings.FORBIDDEN_SLUGS:
            return False
        forbidden_slugs = settings.FORBIDDEN_SLUGS.split(',')

        person_data = staff_api.get_person_data(login=auth.login)
        if not person_data:
            return True

        department_group = person_data['department_group']
        person_department_slugs = [department_group['url']] + [
            ancestor['url'] for ancestor in
            department_group.get('ancestors', [])
        ]
        return bool(set(person_department_slugs) & set(forbidden_slugs))
