"""saml sp views"""
import base64

from defusedxml import ElementTree
from django.contrib.auth import login, logout
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect, render, reverse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

from passbook.providers.saml.base import get_random_id, get_time_string
from passbook.providers.saml.utils import nice64
from passbook.providers.saml.views import render_xml
from passbook.sources.saml.models import SAMLSource
from passbook.sources.saml.utils import (_get_user_from_response,
                                         build_full_url, get_entity_id)
from passbook.sources.saml.xml_render import get_authnrequest_xml


class InitiateView(View):
    """Get the Form with SAML Request, which sends us to the IDP"""

    def get(self, request: HttpRequest, source: str) -> HttpResponse:
        """Replies with an XHTML SSO Request."""
        source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
        if not source.enabled:
            raise Http404
        sso_destination = request.GET.get('next', None)
        request.session['sso_destination'] = sso_destination
        parameters = {
            'ACS_URL': build_full_url('acs', request, source),
            'DESTINATION': source.idp_url,
            'AUTHN_REQUEST_ID': get_random_id(),
            'ISSUE_INSTANT': get_time_string(),
            'ISSUER': get_entity_id(request, source),
        }
        authn_req = get_authnrequest_xml(parameters, signed=False)
        _request = nice64(str.encode(authn_req))
        return render(request, 'saml/sp/login.html', {
            'request_url': source.idp_url,
            'request': _request,
            'token': sso_destination,
            'source': source
        })


@method_decorator(csrf_exempt, name='dispatch')
class ACSView(View):
    """AssertionConsumerService, consume assertion and log user in"""

    def post(self, request: HttpRequest, source: str) -> HttpResponse:
        """Handles a POSTed SSO Assertion and logs the user in."""
        source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
        if not source.enabled:
            raise Http404
        # sso_session = request.POST.get('RelayState', None)
        data = request.POST.get('SAMLResponse', None)
        response = base64.b64decode(data)
        root = ElementTree.fromstring(response)
        user = _get_user_from_response(root)
        # attributes = _get_attributes_from_response(root)
        login(request, user, backend='django.contrib.auth.backends.ModelBackend')
        return redirect(reverse('passbook_core:overview'))


class SLOView(View):
    """Single-Logout-View"""

    def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
        """Replies with an XHTML SSO Request."""
        source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
        if not source.enabled:
            raise Http404
        logout(request)
        return render(request, 'saml/sp/sso_single_logout.html', {
            'idp_logout_url': source.idp_logout_url,
            'autosubmit': source.auto_logout,
        })


class MetadataView(View):
    """Return XML Metadata for IDP"""

    def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
        """Replies with the XML Metadata SPSSODescriptor."""
        source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
        entity_id = get_entity_id(request, source)
        return render_xml(request, 'saml/sp/xml/spssodescriptor.xml', {
            'acs_url': build_full_url('acs', request, source),
            'entity_id': entity_id,
            'cert_public_key': source.signing_cert,
        })