from typing import Set, Dict, Optional

from django_idm_api.conf import IDM_URL_PREFIX

from django import http
from django.conf import settings

from staff.racktables.utils import is_ip_internal
from staff.lib.auth import auth_mechanisms as auth

import logging
logger = logging.getLogger(__name__)


class AccessMiddleware(object):
    views_available_for_external: Dict[str, Optional[str]] = {}
    views_available_by_tvm: Set[str] = set()
    views_forbidden_for_robots: Set[str] = set()
    views_available_by_center_token: Set[str] = set()

    @staticmethod
    def response_forbidden(log_message: str, response_message: str = None) -> http.HttpResponseForbidden:
        logger.warning('AccessMiddleware. Denied access. Reason: "%s"', log_message or '')
        return http.HttpResponseForbidden(response_message or 'Access denied.')

    def is_correct_idm_request(self, request) -> bool:
        return(
            request.auth_mechanism == auth.TVM
            and request.path.startswith('/' + IDM_URL_PREFIX)
            and 'idm' in settings.TVM_APPLICATIONS
            and request.yauser.service_ticket.src == settings.TVM_APPLICATIONS['idm']
        )

    def process_view(self, request, view, args, kwargs) -> Optional[http.HttpResponse]:
        view_name = getattr(view, '__name__', False) or view.__class__.__name__
        auth_mechanism = request.auth_mechanism
        is_real_user = hasattr(request.user, 'get_profile')

        if auth_mechanism in auth.INTERNAL_AUTH_MECHANISMS and not is_ip_internal(request.real_user_ip):
            message = 'Trying to access from external ip'
            return self.response_forbidden(
                log_message=f'{message} ({request.real_user_ip}) with {request.auth_mechanism}',
                response_message=f'Access denied. {message}.'
            )

        if view_name in self.views_forbidden_for_robots and is_real_user and request.user.get_profile().is_robot:
            message = f'Trying to open {view_name} with robot {request.user.username}'
            return self.response_forbidden(log_message=message, response_message=f'Access denied. {message}.')

        if auth_mechanism == auth.ANONYMOUS:
            # only for special views (e.g. monitorings and idm) Checked in AuthMiddleware
            return None

        if auth_mechanism == auth.CENTER:
            if view_name in self.views_available_by_center_token:
                return None
            message = f'Trying to get {view_name} with center authentication'
            return self.response_forbidden(log_message=message, response_message=f'Access denied. {message}.')

        if auth_mechanism == auth.TVM:
            if view_name in self.views_available_by_tvm or self.is_correct_idm_request(request):
                return None

            message = f'Trying to get {view_name} with tvm authentication'
            return self.response_forbidden(log_message=message, response_message=f'Access denied. {message}.')

        if is_real_user and request.user.get_profile().is_internal():
            return None

        if view_name in self.views_available_for_external:
            if not self.views_available_for_external[view_name]:
                # not need permissions
                return None
            if request.user.has_perm(self.views_available_for_external[view_name]):
                return None

        return self.response_forbidden(f'Forbidden access to {view_name} for request with ip {request.real_user_ip}')
