# type: ignore
# Inspired by https://www.silviogutierrez.com/blog/smarter-django-url-tag/

from django.template import TemplateSyntaxError
from django import template
from django.template.defaulttags import URLNode
from django.utils.regex_helper import _lazy_re_compile as re_compile

# from django.template.defaulttags import URLNode, url as url_tag

register = template.Library()
kwarg_re = re_compile(r"(?:(\w+)=)?(.+)")


@register.tag
def url(parser, token):
    # Use builtin method. Might be safer...but creates URLNode twice
    # validator = url_tag(parser, token)
    # return SmartURLNode(validator.view_name, validator.args, validator.kwargs, validator.asvar)

    # copy `url` method and return SmartURLNode, saving the double URLNode creation
    # Something might break in later django releases!
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least one argument, a URL pattern name." % bits[0])
    viewname = parser.compile_filter(bits[1])
    args = []
    kwargs = {}
    asvar = None
    bits = bits[2:]
    if len(bits) >= 2 and bits[-2] == 'as':
        asvar = bits[-1]
        bits = bits[:-2]

    for bit in bits:
        match = kwarg_re.match(bit)
        if not match:
            raise TemplateSyntaxError("Malformed arguments to url tag")
        name, value = match.groups()
        if name:
            kwargs[name] = parser.compile_filter(value)
        else:
            args.append(parser.compile_filter(value))

    return SmartURLNode(viewname, args, kwargs, asvar)


# -------------------------------------------------------------------------
class SmartURL(str):
    """
    This is a wrapper class that allows us to attach
    attributes to regular strings.
    """

    pass


# -------------------------------------------------------------------------
class SmartURLNode(URLNode):
    def render(self, context):
        resolved_url = self.hard_coded_path(context)
        if resolved_url and self.asvar:
            context[self.asvar] = resolved_url

        else:
            resolved_url = super().render(context)

        # If not called in a {% url '<url>' as var %} tag, no further processing needed
        if not self.asvar:
            return resolved_url

        return self.set_active_attributes(context)

    def hard_coded_path(self, context) -> str:
        """
        Handle cases when a hard-coded URL path/string was passed to url tag.
        """
        resolved_view_name = self.view_name.resolve(context)

        if resolved_view_name:
            view_name_string = f"'{resolved_view_name}'"
        else:
            view_name_string = str(self.view_name)

        try:
            if (
                len(view_name_string) >= 3
                and view_name_string[0] == view_name_string[-1]
                and view_name_string[0] in ('"', "'")
                and view_name_string[1] == '/'
            ):
                return view_name_string[1:-1]
        except Exception:
            pass

        return ''

    def set_active_attributes(self, context):
        """
        Add "active" & "active_root" attributes to URL path string
        """
        resolved_url = SmartURL(context[self.asvar])
        request = context.get('request', None)

        if request:
            if resolved_url == request.path:
                resolved_url.active = 'active'
                resolved_url.mm_active = 'mm-active'
            else:
                resolved_url.active = resolved_url.mm_active = ''

            if request.path.startswith(resolved_url):
                resolved_url.active_root = 'active'
                resolved_url.mm_active_root = 'mm-active'
            else:
                resolved_url.active_root = ''
                resolved_url.mm_active_root = ''

        context[self.asvar] = resolved_url
        return ''
