from typing import Any
from django.db import models
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse, reverse_lazy
from django.views.generic.edit import UpdateView 
from django.views.generic.detail import DetailView
from django.shortcuts import get_object_or_404
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.decorators import user_passes_test

from django.db.models import Q
from rcr.filters import ItemFilter, OutcomeFilter

from rcr.models import Item, Outcome, RadiologyCategory
from rcr.forms import AssessorAssignmentForm, ItemForm
from atlas.models import Condition
from django.core.exceptions import PermissionDenied
from loguru import logger

# Create your views here.

def user_is_rcr(function):
    def wrap(request, *args, **kwargs):
        if (
            request.user.groups.filter(Q(name="rcr_radiology_assessor") | Q(name="rcr_oncology_assessor")| Q(name="rcr_assessor")).exists()
            or request.user.is_superuser
        ):
            return function(request, *args, **kwargs)
        else:
            raise PermissionDenied

    wrap.__doc__ = function.__doc__
    wrap.__name__ = function.__name__
    return wrap

def user_is_radiology(user):
    return  user.groups.filter(name="rcr_radiology_assessor").exists()
def user_is_oncology(user):
    return  user.groups.filter(name="rcr_oncology_assessor").exists()

class RCRRequiredMixin(object):
    def get_object(self, *args, **kwargs):
        obj = super().get_object(*args, **kwargs)
        if (
            self.request.user.groups.filter(Q(name="rcr_radiology_assessor") | Q(name="rcr_oncology_assessor")).exists()
            or self.request.user.is_superuser
        ):
            return obj
        if self.request.user not in obj.get_author_objects():
            raise PermissionDenied()  # or Http404

        return obj

@user_is_rcr
def radiology_index_all(request):

    item_filter = ItemFilter(request.GET, queryset=Item.objects.all())

    return render(
        request,
        "rcr/index.html",
        {
            "items": item_filter.qs.prefetch_related("assessed_by"),
            "completed": False,
            "assessor": None,
            "item_filter": item_filter,

        },
    )

@user_is_rcr
def radiology_review(request):
    return redirect(f"{reverse('rcr:radiology_index_all_view')}?needs_review=true")

def radiology_gap(request):
    #items = Item.objects.all().prefetch_related("assessed_by")

    item_filter = OutcomeFilter(request.GET, queryset=Item.objects.all().prefetch_related("assessed_by", "radiology_condition", "radiology_categories", "oncology_category", "outcome", "level"))
    items = item_filter.qs

    categories = RadiologyCategory.objects.all().order_by("name").prefetch_related("items_radiology", "items_radiology__level", "items_radiology__radiology_condition")

    filtered_categories = []

    for category in categories:
        filtered_categories.append((category, item_filter.qs.intersection(category.items_radiology.all())))


    conditions = Condition.objects.all().order_by("name")

    outcomes = Outcome.objects.all().order_by("name")

    return render(request, "rcr/gap.html", {"items": items, 
                                            "item_filter": item_filter,
                                            "filtered_categories": filtered_categories,
                                            "categories": categories,
                                            "conditions": conditions,
                                            "outcomes": outcomes,
                                            })

def radiology_results(request):
    #items = Item.objects.all().prefetch_related("assessed_by")

    item_filter = ItemFilter(request.GET, queryset=Item.objects.all().prefetch_related("assessed_by", "level", "radiology_condition", "radiology_categories", "oncology_category"))
    items = item_filter.qs.prefetch_related("assessed_by")

    return render(request, "rcr/results.html", {"items": items, "item_filter": item_filter})

@user_is_rcr
def radiology_index(request, assigned=True, user_pk: int | None = None):

    assessor = None
    if user_pk is not None:
        assessor = User.objects.get(pk=user_pk)
    elif assigned:
        assessor = request.user

    if assessor is None:
        items = Item.objects.all().exclude(completed_radiology=True).exclude(completed_oncology=True)
    elif assessor.groups.filter(name="rcr_radiology_assessor").exists():
        items = Item.objects.filter(assigned_to_radiology=assessor).exclude(completed_radiology=True)
    elif assessor.groups.filter(name="rcr_oncology_assessor").exists():
        items = Item.objects.filter(assigned_to_oncology=assessor).exclude(completed_oncology=True)
    elif assessor.groups.filter(name="rcr_assessor").exists() or request.user.is_superuser:
        items = Item.objects.all()
        assessor = None
    else:
        raise Http404

    item_filter = ItemFilter(request.GET, queryset=items)

    return render(
        request,
        "rcr/index.html",
        {
            #"items": items,
            "items": item_filter.qs.prefetch_related("assessed_by"),
            "completed": False,
            "assessor": assessor,
            "item_filter": item_filter,

        },
    )

#def radiology_assessor_assignment_rad(request, assessor_pk: int):
#    return radiology_assessor_assignment(request, assessor_pk, "rad")
#def radiology_assessor_assignment_onc(request, assessor_pk: int):
#    return radiology_assessor_assignment(request, assessor_pk, "onc")
#def radiology_assessor_assignment_cross(request, assessor_pk: int):
#    return radiology_assessor_assignment(request, assessor_pk, "cross")

@user_is_rcr
def radiology_assessor_assignment(request, assessor_pk: int, specialty=None):

    item_filter = ItemFilter(request.GET, queryset=Item.objects.all())

    user = get_object_or_404(User, pk=assessor_pk)
    if request.method == "POST":
        assessor_assignment_form = AssessorAssignmentForm(request.POST)
        assessor_assignment_form.fields["items"].queryset = item_filter.qs

        if assessor_assignment_form.is_valid():
            items_to_update = assessor_assignment_form.cleaned_data["items"]


            for item in items_to_update:
                if user_is_radiology(user):
                    item.assigned_to_radiology = user
                elif user_is_oncology(user):
                    item.assigned_to_oncology = user
                else:
                    raise Http404

            if user_is_radiology(user):
                Item.objects.filter(pk__in=items_to_update).bulk_update(items_to_update, ["assigned_to_radiology"])
            elif user_is_oncology(user):
                Item.objects.filter(pk__in=items_to_update).bulk_update(items_to_update, ["assigned_to_oncology"])
            else:
                raise Http404

            return HttpResponseRedirect(reverse("rcr:radiology_assessors_view"))
    else:
        assessor_assignment_form = AssessorAssignmentForm()
        assessor_assignment_form.fields["items"].queryset = item_filter.qs

    return render(
        request,
        "rcr/assessor_assignment_form.html",
        {
            "assessor_assignment_form": assessor_assignment_form,
            "user_to_assign": user,
            "item_filter": item_filter
        },
    )

@user_is_rcr
def radiology_assigned_user(request, user_pk=int):
    return radiology_index(request, user_pk=user_pk)

@user_is_rcr
def radiology_assessors(request):
    rad_assessors = User.objects.filter(groups__name="rcr_radiology_assessor")
    onc_assessors = User.objects.filter(groups__name="rcr_oncology_assessor")


    return render(
        request,
        "rcr/assessors.html",
        {
            "rad_assessors": rad_assessors,
            "onc_assessors": onc_assessors,
        },
    )

@user_is_rcr
def radiology_index_completed_by_user(request, user_pk: int):
    return radiology_index_completed(request, user_pk = user_pk)

@user_is_rcr
def radiology_index_completed(request, user_pk=None):


    assessor = None
    if user_pk is not None:
        assessor = User.objects.get(pk=user_pk)
        if assessor.groups.filter(name="rcr_radiology_assessor").exists():
            items = Item.objects.filter(completed_radiology=True, assessed_by=user_pk).order_by("pk")
        elif assessor.groups.filter(name="rcr_oncology_assessor").exists():
            items = Item.objects.filter(completed_oncology=True, assessed_by=user_pk).order_by("pk")
    else:
        items = Item.objects.filter(Q(completed_radiology=True) | Q(completed_oncology=True))

    item_filter = ItemFilter(request.GET, queryset=items)

    return render(
        request,
        "rcr/index.html",
        {
            "items": item_filter.qs.prefetch_related("assessed_by"),
            "completed": True,
            "assessor": assessor,
            "item_filter": item_filter,
        },
    )


class ItemUpdateBase(UpdateView, RCRRequiredMixin):
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.save()

        form.instance.assessed_by.add(self.request.user.id)
        return super().form_valid(form)

class ItemUpdateView(ItemUpdateBase, RCRRequiredMixin):
    model = Item

    form_class = ItemForm
    template_name = "rcr/item_update.html"
    #excludes = ["rcr_platform_id"]
    #fields = ["category", "level"]

class ItemUpdateNextView(ItemUpdateBase, RCRRequiredMixin):
    model = Item

    form_class = ItemForm
    template_name = "rcr/item_update.html"

    skip = 0

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
        context = super().get_context_data(**kwargs)
        context["skip"] = self.skip

        return context

    def get(self, request, *args, **kwargs):
        try:
            if "skip" in kwargs:
                self.skip = kwargs["skip"]
            self.object = self.get_object()
        except Http404:
            # redirect here
            return redirect("rcr:radiology_index_view")
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)

    def get_object(self):
        user = self.request.user
        if self.skip < 1:
            if user.groups.filter(name="rcr_radiology_assessor").exists():
                obj = Item.objects.filter(assigned_to_radiology=user, completed_radiology=False).order_by("pk").first()
            elif user.groups.filter(name="rcr_oncology_assessor").exists():
                obj = Item.objects.filter(assigned_to_oncology=user, completed_oncology=False).order_by("pk").first()
            else:
                raise Http404
        else:
            try:
                if user.groups.filter(name="rcr_radiology_assessor").exists():
                    obj = Item.objects.filter(assigned_to_radiology=user, completed_radiology=False).order_by("pk")[self.skip]
                elif user.groups.filter(name="rcr_oncology_assessor").exists():
                    obj = Item.objects.filter(assigned_to_oncology=user, completed_oncology=False).order_by("pk")[self.skip]
                else:
                    raise Http404
                #obj = Item.objects.filter(completed=False)[self.skip]
            except IndexError:
                raise Http404

        logger.debug("get_object: retrieving item pk={}", obj)

        if not obj:
            raise Http404

        return obj

    #def get

    def get_success_url(self) -> str:
        return reverse_lazy("rcr:radiology_update_next_view")


    

class ItemDetailView(DetailView, RCRRequiredMixin):
    model = Item
    #template_name = "TEMPLATE_NAME"
    #excludes = ["rcr_platform_id"]
