from builtins import PermissionError

import graphene
import json

from django.db import IntegrityError
from graphene import relay
from graphql_relay import from_global_id

from api.utils import get_object
from basicknowledge.models import BasicKnowledge
from books.models import ContentBlock, Chapter, Module
from notes.inputs import AddNoteArgument, UpdateNoteArgument
from notes.models import ContentBlockBookmark, Note, ChapterBookmark, ModuleBookmark, InstrumentBookmark
from notes.schema import NoteNode


class UpdateContentBookmark(relay.ClientIDMutation):
    class Input:
        uuid = graphene.UUID(required=True)
        content_block = graphene.ID(required=True)
        bookmarked = graphene.Boolean(required=True)

    success = graphene.Boolean()
    errors = graphene.String()

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        uuid = kwargs.get('uuid')
        user = info.context.user
        content_block_id = kwargs.get('content_block')
        bookmarked = kwargs.get('bookmarked')

        content_block = get_object(ContentBlock, content_block_id)

        if bookmarked:
            try:
                ContentBlockBookmark.objects.create(
                    content_block=content_block,
                    uuid=uuid,
                    user=user
                )
            except IntegrityError:
                # already exists, probably fine
                return cls(success=True)
        else:
            ContentBlockBookmark.objects.get(
                content_block=content_block,
                uuid=uuid,
                user=user
            ).delete()

        return cls(success=True)


class AddNote(relay.ClientIDMutation):
    class Input:
        note = graphene.Argument(AddNoteArgument)

    note = graphene.Field(NoteNode)

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        user = info.context.user

        note = kwargs.get('note')
        content_uuid = note.get('content', '')
        content_block_id = note.get('block', '')
        parent = note.get('parent')
        text = note.get('text')

        if content_uuid != '':
            type = note.get('type')
            if type == 'ContentBlockNode':
                content_block = get_object(ContentBlock, content_block_id)

                bookmark = ContentBlockBookmark.objects.get(
                    content_block=content_block,
                    uuid=content_uuid,
                    user=user
                )
            else:
                instrument  = BasicKnowledge.objects.get(slug=content_block_id)
                bookmark = InstrumentBookmark.objects.get(
                    instrument=instrument,
                    uuid=content_uuid,
                    user=user
                )
        else:
            type, id = from_global_id(parent)
            if type == 'ModuleNode':
                bookmark = ModuleBookmark.objects.get(
                    module__id=id,
                    user=user
                )
            else:
                bookmark = ChapterBookmark.objects.get(
                    chapter__id=id,
                    user=user
                )

        bookmark.note = Note.objects.create(text=text)
        bookmark.save()

        return cls(note=bookmark.note)


class UpdateNote(relay.ClientIDMutation):
    class Input:
        note = graphene.Argument(UpdateNoteArgument)

    note = graphene.Field(NoteNode)

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        user = info.context.user

        note = kwargs.get('note')
        id = note.get('id')
        text = note.get('text')
        note = get_object(Note, id)

        if hasattr(note, 'contentblockbookmark') and note.contentblockbookmark.user != user \
            or hasattr(note, 'chapterbookmark') and note.chapterbookmark.user != user \
            or hasattr(note, 'modulebookmark') and note.modulebookmark.user != user:
            raise PermissionError

        note.text = text
        note.save()
        return cls(note=note)


class UpdateChapterBookmark(relay.ClientIDMutation):
    class Input:
        chapter = graphene.ID(required=True)
        bookmarked = graphene.Boolean(required=True)

    success = graphene.Boolean()

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        user = info.context.user
        chapter_id = kwargs.get('chapter')
        bookmarked = kwargs.get('bookmarked')

        chapter = get_object(Chapter, chapter_id)

        if bookmarked:
            ChapterBookmark.objects.create(
                chapter=chapter,
                user=user
            )
        else:
            ChapterBookmark.objects.get(
                chapter=chapter,
                user=user
            ).delete()

        return cls(success=True)


class UpdateModuleBookmark(relay.ClientIDMutation):
    class Input:
        module = graphene.String(required=True)
        bookmarked = graphene.Boolean(required=True)

    success = graphene.Boolean()

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        user = info.context.user
        module_slug = kwargs.get('module')
        bookmarked = kwargs.get('bookmarked')

        module = Module.objects.get(slug=module_slug)

        if bookmarked:
            ModuleBookmark.objects.create(
                module=module,
                user=user
            )
        else:
            ModuleBookmark.objects.get(
                module=module,
                user=user
            ).delete()

        return cls(success=True)


class UpdateInstrumentBookmark(relay.ClientIDMutation):
    class Input:
        uuid = graphene.UUID(required=True)
        instrument = graphene.String(required=True)
        bookmarked = graphene.Boolean(required=True)

    success = graphene.Boolean()

    @classmethod
    def mutate_and_get_payload(cls, root, info, **kwargs):
        user = info.context.user
        instrument_slug = kwargs.get('instrument')
        uuid = kwargs.get('uuid')
        bookmarked = kwargs.get('bookmarked')

        instrument = BasicKnowledge.objects.get(slug=instrument_slug)

        if bookmarked:
            try:
                InstrumentBookmark.objects.create(
                    instrument=instrument,
                    uuid=uuid,
                    user=user
                )
            except IntegrityError:
                # already exists, that's probably ok
                return cls(success=True)
        else:
            InstrumentBookmark.objects.get(
                instrument=instrument,
                uuid=uuid,
                user=user
            ).delete()

        return cls(success=True)


class NoteMutations:
    add_note = AddNote.Field()
    update_note = UpdateNote.Field()
    update_content_bookmark = UpdateContentBookmark.Field()
    update_chapter_bookmark = UpdateChapterBookmark.Field()
    update_module_bookmark = UpdateModuleBookmark.Field()
    update_instrument_bookmark = UpdateInstrumentBookmark.Field()
