import typing

from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

from BaseLib.BaseEntity import BaseEntity
from BaseLib.bot import notify_if_needed


class AccessError(Exception):
    pass


class BaseView(BaseEntity):
    request: WSGIRequest
    context: typing.Optional[typing.Dict] = None
    required_login: typing.Optional[bool] = None
    view_file: typing.Optional[str] = None
    endpoint: typing.Optional[str] = None
    fields_except: typing.Tuple[str] = ()

    def __init__(self, request):
        self.context = {}
        self.request = request

    def get_user(self):
        return self.request.user

    @classmethod
    def as_path(cls):
        return cls.endpoint, cls.as_view()

    @classmethod
    def as_view(cls):
        @csrf_exempt
        def execute(request: WSGIRequest):
            try:
                c = cls(request)
                if c.required_login is not None:
                    if c.required_login and not request.user.is_authenticated:
                        return HttpResponseRedirect("/welcome")
                    if (
                        not c.required_login
                        and request.user.is_authenticated
                    ):
                        return HttpResponseRedirect("/")
                request_method = request.method.lower()
                exec("from Platform.common_models import *")
                context = {}
                for key in request.GET.keys():
                    if key.endswith("_id") and key not in cls.fields_except:
                        model_name = key[:-3]
                        setattr(
                            c,
                            model_name,
                            eval(model_name[0].upper() + model_name[1:]).objects.get(
                                id=int(request.GET[key])
                            ),
                        )
                        context[model_name] = getattr(c, model_name)
                if "action" in request.POST.keys():
                    request_method += "_" + request.POST["action"]
                method = getattr(c, request_method, None)
                try:
                    data = c.pre_handle()
                    if method:
                        if data is None:
                            data = method()
                        if isinstance(data, BaseView):
                            return HttpResponseRedirect(data.endpoint)
                        if type(data) == str:
                            return HttpResponseRedirect(data)
                        if type(data) == dict:
                            return JsonResponse(data)
                        if data is not None:
                            return data
                    context = {**context, **c.context}
                    res = render(request, c.view_file, context)
                    res.headers["X-Frame-Options"] = "ALLOW"
                    return res
                except AccessError:
                    return HttpResponseRedirect("/")
            except Exception as exc:
                print(exc)
                notify_if_needed(exc)
                raise

        return execute

    def pre_handle(self):
        pass

    def get(self):
        pass

    def post(self):
        pass
