import json
from django.test import TestCase
from django.urls import reverse
from wagtail.models import Page
from wagtail.test.utils import WagtailTestUtils
from assignments.factories import AssignmentFactory
from assignments.models import Assignment
from books.blocks import AssignmentBlock, SurveyBlock
from books.factories import BookFactory, ChapterFactory, ModuleFactory, TopicFactory
from books.models.contentblock import ContentBlock
from books.models.module import Module
from books.models.topic import Topic

from core.logger import get_logger
from surveys.factories import SurveyFactory
from surveys.models import Survey

logger = get_logger(__name__)


def get_copy_payload(title, slug, parent):
    return {
        "new_title": title,
        "new_slug": slug,
        "new_parent_page": parent.id,
        "copy_subpages": True,
        "publish_copies": False,
        "alias": False,
    }


def get_copy_url(page):
    return reverse("wagtailadmin_pages:copy", args=(page.id,))


class CoreHooksTestCase(WagtailTestUtils, TestCase):
    def setUp(self) -> None:
        (
            self.book,
            self.topic,
            self.module,
            self.chapter,
            self.content_block,
        ) = BookFactory.create_default_structure()
        self.user = self.login()

        # create content blocks
        assignment = AssignmentFactory()
        self.assignment_id = assignment.id
        assignment_block = AssignmentBlock()
        assignment_value = assignment_block.to_python({"assignment_id": assignment.id})
        cleaned_assignment_value = assignment_block.clean(assignment_value)
        assignment_content = ("assignment", cleaned_assignment_value)

        survey = SurveyFactory()
        survey_block = SurveyBlock()
        survey_value = survey_block.to_python({"survey_id": survey.id})
        cleaned_survey_value = survey_block.clean(survey_value)
        survey_content = ("survey", cleaned_survey_value)

        self.content_block.contents.append(assignment_content)
        self.content_block.contents.append(survey_content)
        self.content_block.save()

        self.assertEqual(
            self.content_block.contents[0].value["assignment_id"], assignment
        )
        self.assertEqual(self.content_block.contents[1].value["survey_id"], survey)
        self.assertEqual(Assignment.objects.count(), 1)
        self.assertEqual(Survey.objects.count(), 1)
        # logger.debug(f"assignment: {assignment.id}")

        self.new_topic = TopicFactory.create(
            parent=self.book, title="A second Topic", order=2
        )

        self.new_module = ModuleFactory.create(
            parent=self.new_topic,
            title="A second module",
            meta_title="Modul 1",
            teaser="Whatever",
            intro="<p>Hello</p>",
        )
        self.new_chapter = ChapterFactory.create(
            parent=self.new_module, title="A second chapter"
        )

    def test_after_create_hook(self):
        # description = rich_text('<p>hello</p>')
        self.assertEqual(Topic.objects.count(), 2)
        description = {
            "blocks": [
                {
                    "key": "thfb4",
                    "text": "asd",
                    "type": "unstyled",
                    "depth": 0,
                    "inlineStyleRanges": [],
                    "entityRanges": [],
                    "data": {},
                }
            ],
            "entityMap": {},
        }
        post_data = {
            "title": "New Page",
            "order": 1,
            "teaser": "Tease",
            "description": json.dumps(description),
            "slug": "hello-world",
        }
        url = reverse(
            "wagtailadmin_pages:add",
            args=("books", "topic", self.book.id),
        )
        # logger.debug(url)
        self.client.post(
            url,
            post_data,
        )
        self.assertEqual(Topic.objects.count(), 3)

    def _check_copied_content_block(self, module=None):
        if module is None:
            module = self.new_module

        self.assertEqual(ContentBlock.objects.count(), 2)
        self.assertEqual(Assignment.objects.count(), 2)
        self.assertEqual(Survey.objects.count(), 2)
        new_content_block = ContentBlock.objects.latest("-latest_revision_created_at")
        new_assignment = Assignment.objects.latest("pk")
        new_survey = Survey.objects.latest("pk")
        self.assertEqual(
            new_content_block.contents[0].value["assignment_id"], new_assignment
        )
        self.assertEqual(new_assignment.module, module)
        self.assertEqual(new_content_block.contents[1].value["survey_id"], new_survey)
        self.assertEqual(new_survey.module, module)

    def test_content_block_after_copy_hook(self):
        """
        should copy the content block, and set all entities' module to the new parent's parent module
        """
        # inspired by wagtail.admin.tests.pages.test_copy_page

        url = get_copy_url(self.content_block)
        post_data = get_copy_payload(
            "Neuer Titel (Kopie)", "new-slug", self.new_chapter
        )
        self.client.post(url, post_data)
        self._check_copied_content_block()

    def test_chapter_after_copy_hook(self):
        """
        should copy the chapter, and set all entities' module to the new parent module
        """
        url = get_copy_url(self.chapter)
        post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.new_module)
        self.client.post(url, post_data)
        self._check_copied_content_block()

    def test_module_after_copy_hook(self):
        """
        should copy the module, and set all entities' module to the newly created module
        """
        url = get_copy_url(self.module)
        post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.new_topic)
        self.client.post(url, post_data)
        module = Module.objects.latest("-latest_revision_created_at")
        self._check_copied_content_block(module)

    def test_topic_after_copy_hook(self):
        """
        should copy the whole topic, and set all entities to the newly created child module
        """
        url = get_copy_url(self.topic)
        post_data = get_copy_payload("Neuer Titel (Kopie)", "new-slug", self.book)
        self.client.post(url, post_data)
        topic = Topic.objects.latest("-latest_revision_created_at")
        module = topic.get_children().first().specific
        self._check_copied_content_block(module)

    # def test_chapter_after_move_hook(self):
    #     """
    #     should move the chapter, and set all entities' module to the new parent's parent module
    #     """
    #
    #     assignment = self.content_block.contents[0].value["assignment_id"]
    #     survey = self.content_block.contents[1].value["survey_id"]
    #     self.assertEqual(self.chapter.pk, self.content_block.get_parent().pk)
    #
    #     logger.debug("content blocks")
    #     logger.debug(self.chapter.get_content_blocks())
    #
    #     url = reverse(
    #         "wagtailadmin_pages:move_confirm",
    #         args=(self.chapter.id, self.new_module.id),
    #     )
    #     logger.debug(url)
    #     response = self.client.post(url)
    #     logger.debug(response)
    #     chapter = Page.objects.get(id=self.chapter.id)
    #     logger.debug("new content blocks")
    #     logger.debug(chapter.specific.get_content_blocks())
    #     self.assertEqual(chapter.get_parent().id, self.new_module.id)
    #     # reload the assignment from the DB
    #     assignment = Assignment.objects.get(id=assignment.id)
    #     self.assertEqual(assignment.module, self.new_module)
    #     survey = Survey.objects.get(id=survey.id)
    #     self.assertEqual(survey.module, self.new_module)

    # def test_content_block_after_move_hook(self):
    #     """
    #     should move the content block, and set all entities' module to the new parent's parent module
    #     """
    #
    #     url = reverse(
    #         "wagtailadmin_pages:move_confirm",
    #         args=(self.content_block.id, self.new_chapter.id),
    #     )
    #     self.client.post(url)
    #     assignment = self.content_block.contents[0].value["assignment_id"]
    #     self.assertEqual(assignment.module, self.new_module)

    def test_content_block_after_create_hook(self):
        """
        should save the content block and set all new entites' module to the correct module
        """
        assignment = AssignmentFactory(module=self.module)
        survey = SurveyFactory(module=None)
        self.assertEqual(assignment.module, assignment.module)
        self.assertIsNone(survey.module)
        self.assertEqual(ContentBlock.objects.count(), 1)
        url = reverse(
            "wagtailadmin_pages:add",
            args=("books", "contentblock", self.new_chapter.id),
        )
        post_data = {
            "title": "New Content Block",
            "order": 1,
            "slug": "hello-world",
            "contents-count": 2,
            "contents-0-deleted": "",
            "contents-0-order": "0",
            "contents-0-type": "assignment",
            "contents-0-id": "",
            "contents-0-value-assignment_id": f"{assignment.id}",
            "contents-1-deleted": "",
            "contents-1-order": "1",
            "contents-1-type": "survey",
            "contents-1-id": "",
            "contents-1-value-survey_id": f"{survey.id}",
            "type": "normal",
        }
        response = self.client.post(
            url,
            post_data,
        )
        self.assertEqual(ContentBlock.objects.count(), 2)
        # reload assignment
        assignment = Assignment.objects.get(id=assignment.id)
        self.assertEqual(assignment.module, self.new_module)
        survey = Survey.objects.get(id=survey.id)
        self.assertEqual(survey.module, self.new_module)
