from os.path import join, split, splitext
from importlib import import_module

from django import template
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe

from ocyan.core.fender import config

from oxyan.themes import definitions

register = template.Library()


# pylint: disable=no-member
if "ocyan.plugin.wagtail" in config.ocyan_plugins:
    from wagtail.models import Site

    from oxyan.themes.models import PageMenuProxy

    @register.simple_tag(takes_context=True)
    def rootpage_as_category(context):
        request = context["request"]
        site = Site.find_for_request(request)
        root_page = site.root_page.specific.localized
        return PageMenuProxy.from_page(root_page, request=request, site=site)

    @register.simple_tag(takes_context=True)
    def main_navigation_pages(context):
        """Returns the pages to render in a menu in order."""
        request = context["request"]
        site = Site.find_for_request(request)
        root_page = site.root_page
        root_page_proxy = PageMenuProxy.from_page(root_page, request=request, site=site)
        pages = root_page_proxy.get_children().live().in_menu()
        return pages

else:

    @register.simple_tag
    def rootpage_as_category():
        return None

    @register.simple_tag
    def main_navigation_pages():
        return []


@register.filter(name="is_selected")
def value(tree_category, category):
    return category.path.startswith(tree_category.path[:-4])


@register.simple_tag
def rootimage(category):
    for cat in category.get_ancestors_and_self():
        if cat.image:
            return cat.image.url


@register.filter(name="startswith")
def startswith_tag(tree_category, category):
    return category.path.startswith(tree_category.path)


@register.simple_tag(takes_context=True)
def include_header(context, template_path):
    """
    select a header specific filename

    >>> include_header("partials/blaat/koe.html")
    "partials/blaat/header1.html"
    >>> include_header("partials/blaat/koe.css")
    "partials/blaat/header1.css"
    """
    path, basename = split(template_path)
    _, ext = splitext(basename)

    return render_to_string(
        join(path, "%s%s" % (definitions.get("header", "basic"), ext)),
        context=context.flatten(),
    )


@register.inclusion_tag(
    "templatetags/ocyan_wagtail/main_navigation.html", takes_context=True
)
def render_main_navigation_items(context, max_depth=999):
    """Renders the main navigation items"""
    pages = main_navigation_pages(context)
    current_page = context.get("page")
    current_path = getattr(current_page, "path", "") if current_page else ""

    def wrap(pages, current_depth=0):
        current_depth += 1
        for item in pages:
            if max_depth > current_depth:
                children = list(
                    wrap(item.get_children().live().in_menu(), current_depth)
                )
            else:
                children = []
            yield {
                "page": item,
                "is_active": current_path.startswith(item.path),
                "children": children,
            }

    return {"pages": list(wrap(pages)), "current_page": current_page}


@register.tag(name="captureas")
def do_captureas(parser, token):
    try:
        tag_name, args = token.contents.split(None, 1)  # pylint: disable=W0612
    except ValueError:
        raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
    nodelist = parser.parse(("endcaptureas",))
    parser.delete_first_token()
    return CaptureasNode(nodelist, args)


class CaptureasNode(template.Node):
    def __init__(self, nodelist, varname):
        self.nodelist = nodelist
        self.varname = varname

    def render(self, context):
        output = self.nodelist.render(context)
        context[self.varname] = output
        return ""


@register.simple_tag
def get_oxyan_definition(name):
    return definitions.get(name)


def _render_optional_ai_assistant_widget(context):
    try:
        module = import_module(
            "ocyan.plugin.ai_assistant.templatetags.ai_assistant_tags"
        )
        widget_context = module.ai_assistant_widget(context)
    except Exception:
        return ""

    if not widget_context.get("render_widget"):
        return ""

    return render_to_string(
        "ai_assistant/includes/chat_widget.html",
        widget_context,
        request=context.get("request"),
    )


@register.simple_tag(takes_context=True)
def optional_ai_assistant_widget(context):
    return mark_safe(_render_optional_ai_assistant_widget(context))


@register.simple_tag(takes_context=True)
def get_pages(context, paginator, on_each_side):
    current_page = context["request"].GET.get("page", 1)
    pages = paginator.get_elided_page_range(
        current_page, on_each_side=on_each_side, on_ends=1
    )
    page_choices = ""

    for page in pages:
        # Elasticsearch gives an error when you have selected a product past 10k
        # so dont show the last page button when there are 10k or more products
        if page == paginator.num_pages and paginator.count >= 10000:
            continue
        extra_context = {}
        extra_context["page_number"] = page

        if page == paginator.ELLIPSIS:
            extra_context["ellipsis"] = True
        elif int(page) == int(current_page):
            extra_context["is_current_page"] = True

        page_choices = page_choices + render_to_string(
            "oscar/partials/page_link.html", context.flatten() | extra_context
        )

    return mark_safe(page_choices)
