import logging

from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django_yauth.authentication_mechanisms.tvm import Mechanism as TVMMechamism, TvmRequest
from django_yauth.user import DjangoUserDescriptor, YandexUser, YandexTestUser

from idm.utils.tvm import get_tvm_client

log = logging.getLogger(__name__)


class Mechanism(TVMMechamism):
    """
    Механизм аутентификации по TVM с подменненным TVM-клиентом
    """
    def __init__(self):
        self.tvm = get_tvm_client()

    @property
    def mechanism_name(self):
        return 'tvm'


class IDMUserDescriptor(DjangoUserDescriptor):
    """По аналогии с django_yauth.user.DjangoUserDescriptor"""

    def __get__(self, request, owner):
        if request is None:
            return self

        if not hasattr(request, '_user'):
            user = AnonymousUser()
            yauser: YandexUser = request.yauser

            if yauser.is_authenticated():
                if not getattr(yauser, 'is_impersonated', True):
                    # TVM Service Ticket
                    identity_field = 'username'
                    identity_value = yauser.service_ticket.src
                else:
                    # OAuth/Cookie/TVM User Ticket
                    identity_field = 'uid'
                    identity_value = yauser.uid

                user_cls = get_user_model()
                try:
                    if identity_value:
                        user = user_cls.objects.get(**{identity_field: identity_value})
                except user_cls.DoesNotExist:
                    log.warning(
                        'User not found by %s=%s using %s mechanism',
                        identity_field,
                        identity_value,
                        yauser.authenticated_by.mechanism_name,
                    )

            request._user = user
        return request._user


class IDMTestUserDescriptor(DjangoUserDescriptor):
    def __get__(self, request, owner):
        if request is None:
            return self

        if not hasattr(request, '_user'):
            yauser: YandexUser = request.yauser

            user = AnonymousUser()
            if yauser.is_authenticated():
                if isinstance(yauser, YandexTestUser) and settings.YAUTH_TEST_USER and yauser.login:
                    user_cls = get_user_model()
                    try:
                        user = user_cls.objects.get(**{'username': yauser.login})
                    except user_cls.DoesNotExist:
                        pass

            request._user = user or AnonymousUser()
        return request._user
