import wagtail.admin.views.pages.ordering
from django.db.models import ProtectedError
from django.shortcuts import redirect
from wagtail.admin import messages
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
from wagtail.admin.rich_text.converters.html_to_contentstate import (
    InlineStyleElementHandler,
)
from wagtail import hooks
from wagtail.admin.utils import get_valid_next_url_from_request

from basicknowledge.models import BasicKnowledge
from books.models import ContentBlockSnapshot
from books.models.chapter import Chapter
from books.models.contentblock import ContentBlock
from core.logger import get_logger
from django.conf import settings
from .wagtail_patch import set_page_position

logger = get_logger(__name__)

theme = settings.THEME
if theme == "my-kv":
    primary = "#2075ff"
    secondary = "#0fd6a0"
elif theme == "my-dha":
    primary = "#1bab4e"
    secondary = "#139ee0"
elif theme == "my-dhf":
    primary = "#139ee0"
    secondary = "#1bab4e"
else:
    primary = "#17A887"
    secondary = "#078CC6"

# Monkey patching wagtail.admin.views.pages.ordering.set_page_position because there is a bug in the original code
# github issue:

wagtail.admin.views.pages.ordering.set_page_position = set_page_position


# 1. Use the register_rich_text_features hook.
@hooks.register("register_rich_text_features")
def register_brand_feature(features):
    """
    Registering the feature, which uses the `BRAND` Draft.js inline style type,
    and is stored as HTML with a `<span class="brand">` tag.
    """
    feature_name = "brand"
    type_ = "BRAND"

    # 2. Configure how Draftail handles the feature in its toolbar.
    control = {
        "type": type_,
        "label": "Auszeichung Primär",
        "description": "Auszeichung Primär",
        "style": {"color": primary, "font-weight": "600"},
    }

    # 3. Call register_editor_plugin to register the configuration for Draftail.
    features.register_editor_plugin(
        "draftail", feature_name, draftail_features.InlineStyleFeature(control)
    )

    # 4.configure the content transform from the DB to the editor and back.
    db_conversion = {
        "from_database_format": {
            'span[class="brand"]': InlineStyleElementHandler(type_)
        },
        "to_database_format": {"style_map": {type_: 'span class="brand""'}},
    }

    # 5. Call register_converter_rule to register the content transformation conversion.
    features.register_converter_rule("contentstate", feature_name, db_conversion)

    # 6. (optional) Add the feature to the default features list to make it available
    # on rich text fields that do not specify an explicit 'features' list
    features.default_features.append(feature_name)


@hooks.register("register_rich_text_features")
def register_secondary_feature(features):
    """
    Registering the feature, which uses the `SECONDARY` Draft.js inline style type,
    and is stored as HTML with a `<span class="secondary">` tag.
    """
    feature_name = "secondary"
    type_ = "SECONDARY"

    # 2. Configure how Draftail handles the feature in its toolbar.
    control = {
        "type": type_,
        "label": "Auszeichnung sekundär",
        "description": "Auszeichnung sekundär",
        "style": {"color": secondary, "font-weight": "600"},
    }

    # 3. Call register_editor_plugin to register the configuration for Draftail.
    features.register_editor_plugin(
        "draftail", feature_name, draftail_features.InlineStyleFeature(control)
    )

    # 4.configure the content transform from the DB to the editor and back.
    db_conversion = {
        "from_database_format": {
            'span[class="secondary"]': InlineStyleElementHandler(type_)
        },
        "to_database_format": {"style_map": {type_: 'span class="secondary"'}},
    }

    # 5. Call register_converter_rule to register the content transformation conversion.
    features.register_converter_rule("contentstate", feature_name, db_conversion)

    # 6. (optional) Add the feature to the default features list to make it available
    # on rich text fields that do not specify an explicit 'features' list
    features.default_features.append(feature_name)


@hooks.register("construct_explorer_page_queryset")
def remove_page_types_from_menu(parent_page, pages, request):
    # Modify the queryset used to populate the explorer menu, to exclude content that is created by the teachers.
    # or: Show only content that is created by the content team.
    return (
        pages.not_type(ContentBlockSnapshot)
        .not_type(BasicKnowledge)
        .exclude(contentblock__user_created=True)
    )


@hooks.register("after_copy_page")
def after_copy_hook(request, page, new_page):
    # todo: find every ContentBlock further down in the tree, see if there are any Surveys or Assignments and copy them and reassign them
    if type(page.specific) == ContentBlock:
        # logger.debug("It's a content block")
        content_block: ContentBlock = new_page.specific
        # logger.debug(f"duplicatin {content_block.title, content_block.pk}")
        content_block.duplicate_attached_entities()

    else:
        # logger.debug(f"It's something else {type(page.specific)}, {ContentBlock}")
        content_blocks = new_page.specific.get_content_blocks()
        for content_block in content_blocks:
            content_block.duplicate_attached_entities()


@hooks.register("after_move_page")
def after_move_hook(request, page):
    logger.debug(f"after moving the page {page.title}")
    if type(page.specific) == ContentBlock:
        logger.debug("it's a content block")
        page.specific.reassign_entities()
    if type(page.specific) == Chapter:
        logger.debug("it's a chapter")
        content_blocks = page.specific.get_content_blocks()
        logger.debug(page.id)
        logger.debug(page.specific.get_content_blocks())
        logger.debug(page.get_children())
        for content_block in content_blocks:
            content_block.reassign_entities()


@hooks.register("after_edit_page")
def after_edit_hook(request, page):
    logger.debug(f"After edit page {page.title}, {type(page).__name__}")


@hooks.register("after_create_page")
def after_create_hook(request, page):
    # reassign assignment and survey module
    if type(page.specific) == ContentBlock:
        content_block = page.specific
        content_block.reassign_entities()


@hooks.register("before_delete_page")
def on_page_delete(request, page):
    if request.method != "POST":
        return

    try:
        next_url = get_valid_next_url_from_request(request)
        parent_id = page.get_parent().id
        page.delete()

        messages.success(
            request, ("Page '{0}' deleted.").format(page.get_admin_display_title())
        )

        for fn in hooks.get_hooks("after_delete_page"):
            result = fn(request, page)
            if hasattr(result, "status_code"):
                return result

        if next_url:
            return redirect(next_url)
        return redirect("wagtailadmin_explore", parent_id)

    except ProtectedError as exc:
        protected_objects = {}
        for obj in exc.protected_objects:
            model_name = obj._meta.verbose_name_plural
            if model_name in protected_objects:
                protected_objects[model_name].append(str(obj))
            else:
                protected_objects[model_name] = [str(obj)]

        dependency_summary = []
        for model_name, items in protected_objects.items():
            if len(items) == 1:
                items_summary = ("{0} ({1})").format(model_name, items[0])
            else:
                items_summary = ("{0} ({1} and {2} more...)").format(
                    model_name, items[0], len(items) - 1
                )

            dependency_summary.append(items_summary)

        messages.error(
            request,
            ("Page '{0}' cannot be deleted while it's used by {1}").format(
                page.get_admin_display_title(), ", ".join(dependency_summary)
            ),
        )
        return redirect("wagtailadmin_pages:delete", page.id)
