from typing import Any

from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.clickjacking import xframe_options_sameorigin

from authentik.endpoints.models import EndpointStage
from authentik.enterprise.endpoints.connectors.google_chrome.controller import (
    HEADER_ACCESS_CHALLENGE_RESPONSE,
    HEADER_DEVICE_TRUST,
    GoogleChromeController,
)
from authentik.enterprise.endpoints.connectors.google_chrome.models import GoogleChromeConnector
from authentik.flows.planner import PLAN_CONTEXT_DEVICE, FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN


@method_decorator(xframe_options_sameorigin, name="dispatch")
class GoogleChromeDeviceTrustConnector(View):
    """Google Chrome Device-trust connector based endpoint authenticator"""

    def get_flow_plan(self) -> FlowPlan:
        flow_plan: FlowPlan = self.request.session[SESSION_KEY_PLAN]
        return flow_plan

    def setup(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
        super().setup(request, *args, **kwargs)
        stage: EndpointStage = self.get_flow_plan().bindings[0].stage
        connector = GoogleChromeConnector.objects.filter(pk=stage.connector_id).first()
        if not connector:
            return HttpResponseBadRequest()
        self.controller: GoogleChromeController = connector.controller(connector)

    def get(self, request: HttpRequest) -> HttpResponse:
        x_device_trust = request.headers.get(HEADER_DEVICE_TRUST)
        x_access_challenge_response = request.headers.get(HEADER_ACCESS_CHALLENGE_RESPONSE)
        if x_device_trust == "VerifiedAccess" and x_access_challenge_response is None:
            return self.controller.generate_challenge(request)
        if x_access_challenge_response:
            device = self.controller.validate_challenge(x_access_challenge_response)
            flow_plan = self.get_flow_plan()
            flow_plan.context[PLAN_CONTEXT_DEVICE] = device
            self.request.session[SESSION_KEY_PLAN] = flow_plan
        return TemplateResponse(request, "flows/frame-submit.html")
