import logging

import graphene
from graphene import relay
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField

from api.utils import get_by_id_or_slug, get_object
from rooms.models import Comment, ModuleRoomSlug, Room, RoomEntry
from users.models import SchoolClass
from users.schema import PublicUserNode

logger = logging.getLogger(__name__)


class CommentNode(DjangoObjectType):
    owner = graphene.Field(PublicUserNode)

    class Meta:
        model = Comment
        interfaces = (relay.Node,)
        filter_fields = ['owner', ]
        only_fields = ('owner', 'text', 'created')


class RoomEntryNode(DjangoObjectType):
    pk = graphene.Int()
    author = graphene.Field('users.schema.PublicUserNode')
    comments = DjangoFilterConnectionField(CommentNode)

    class Meta:
        model = RoomEntry
        filter_fields = ['slug']
        interfaces = (relay.Node,)

    def resolve_pk(self, *args, **kwargs):
        return self.id


class RoomNode(DjangoObjectType):
    pk = graphene.Int()
    entry_count = graphene.Int()

    class Meta:
        model = Room
        filter_fields = ['slug', 'appearance']
        interfaces = (relay.Node,)

    def resolve_pk(self, *args, **kwargs):
        return self.id

    def resolve_entry_count(self, *args, **kwargs):
        return self.room_entries.count()

    @staticmethod
    def resolve_room_entries(root: Room, info, **kwargs):
        user = info.context.user
        if root.restricted and not user.is_teacher():
            return root.room_entries.filter(author=user)
        else:
            return root.room_entries.all()



class RoomsQuery(object):
    # room = relay.Node.Field(RoomNode)
    room_entry = graphene.Field(RoomEntryNode, id=graphene.ID(), slug=graphene.String())
    room = graphene.Field(RoomNode, slug=graphene.String(), id=graphene.ID(), appearance=graphene.String())

    rooms = DjangoFilterConnectionField(RoomNode)
    all_room_entries = DjangoFilterConnectionField(RoomEntryNode)

    def resolve_rooms(self, info, **kwargs):
        user = info.context.user
        if user.is_superuser:
            return Room.objects.all()
        return Room.objects.filter(school_class__in=user.school_classes.all()).exclude(user_created=False)

    def resolve_room(self, info, **kwargs):
        room = get_by_id_or_slug(Room, **kwargs)
        if room.school_class.is_user_in_schoolclass(info.context.user):
            return room
        else:
            return None

    def resolve_room_entry(self, info, **kwargs):
        slug = kwargs.get('slug')
        id = kwargs.get('id')
        room_entry = None

        if id is not None:
            room_entry = get_object(RoomEntry, id)
        if slug is not None:
            room_entry = RoomEntry.objects.get(slug=slug)

        if room_entry and room_entry.can_user_see_entry(info.context.user):
            return room_entry
        else:
            return None

    def resolve_all_room_entries(self, info, **kwargs):
        if not info.context.user.is_superuser:
            return RoomEntry.objects.none()
        else:
            return RoomEntry.objects.all()


class ModuleRoomsQuery(object):
    module_room = graphene.Field(RoomNode, slug=graphene.String(), class_id=graphene.ID())

    def resolve_module_room(self, info, **kwargs):
        schoolclass = get_object(SchoolClass, kwargs.get('class_id'))

        try:
            slug = ModuleRoomSlug.objects.get(slug=kwargs.get('slug'))
        except ModuleRoomSlug.DoesNotExist:
            return None

        if schoolclass is None or not schoolclass.is_user_in_schoolclass(info.context.user):
            return None

        room, created = Room.objects.get_or_create(school_class=schoolclass, user_created=False, slug=slug.slug,
                                                   title=slug.title, appearance='blue')
        if created:
            room.slug = slug.slug
            room.save()

        if not room.user_created and room.school_class.is_user_in_schoolclass(info.context.user):
            return room
        else:
            return None
