import json
import random

from django import template, forms
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.template.loader import render_to_string
from django.urls import reverse

from aircox.models import Diffusion, Log


random.seed()
register = template.Library()


@register.filter(name="admin_url")
def admin_url(obj, action):
    meta = obj._meta
    return reverse(f"admin:{meta.app_label}_{meta.model_name}_{action}", args=[obj.id])


@register.simple_tag(name="page_widget", takes_context=True)
def do_page_widget(context, widget, object, dir="aircox/widgets", **ctx):
    """Render widget for the provided page and context."""
    ctx["request"] = context["request"]
    ctx["object"] = object
    ctx["widget"] = widget
    if object.pk and not ctx.get("tag_id"):
        model = type(object)._meta.model_name
        ctx["tag_id"] = f"{widget}_{model}_{object.pk}"
    ctx["widget_template"] = f"{dir}/{widget}.html"
    return render_to_string(object.get_template_name(widget), ctx)


@register.filter(name="page_template")
def do_page_template(self, page, component):
    """For a provided page object and component name, return template name."""
    return page.get_template(component)


@register.filter(name="admin_url")
def do_admin_url(obj, arg, pass_id=True):
    """Reverse admin url for object."""
    name = admin_urlname(obj._meta, arg)
    return reverse(name, args=(obj.id,)) if pass_id else reverse(name)


@register.filter(name="get_tracks")
def do_get_tracks(obj):
    """Get a list of track for the provided log, diffusion, or episode."""
    if isinstance(obj, Log):
        return (obj.track,)

    if isinstance(obj, Diffusion):
        obj = obj.episode
    return obj.track_set.all()


@register.simple_tag(name="has_perm", takes_context=True)
def do_has_perm(context, obj, perm, user=None, simple=False):
    """Return True if ``user.has_perm('[APP].[perm]_[MODEL]')``"""
    if not obj:
        return
    if user is None:
        user = context["request"].user
    if simple:
        return user.has_perm("aircox.{}".format(perm)) or user.is_superuser
    else:
        return user.has_perm("{}.{}_{}".format(obj._meta.app_label, perm, obj._meta.model_name))


@register.filter(name="is_diffusion")
def do_is_diffusion(obj):
    """Return True if object is a Diffusion."""
    return isinstance(obj, Diffusion)


@register.filter(name="is_log")
def do_is_log(obj):
    """Return True if object is a Diffusion."""
    return isinstance(obj, Log)


@register.filter(name="json")
def do_json(obj, fields=""):
    """Return object as json."""
    if fields:
        obj = {k: getattr(obj, k, None) for k in ",".split(fields)}
    return json.dumps(obj)


@register.simple_tag(name="player_live_attr", takes_context=True)
def do_player_live_attr(context):
    """Player 'live-args' attribute value."""
    station = getattr(context["request"], "station", None)
    return json.dumps(
        {
            "url": reverse("api:live"),
            "src": station and station.audio_streams.split("\n"),
        }
    )


@register.simple_tag(name="nav_items", takes_context=True)
def do_nav_items(context, menu, **kwargs):
    """Render navigation items for the provided menu name."""
    if not getattr(context["request"], "station"):
        return []
    station, request = context["station"], context["request"]
    return [(item, item.render(request, **kwargs)) for item in station.navitem_set.filter(menu=menu)]


@register.filter(name="nav_active")
def do_nav_active(obj, request):
    if request.path.startswith(obj.get_url()):
        return True
    return False


@register.simple_tag(name="update_query")
def do_update_query(obj, **kwargs):
    """Replace provided querydict's values with **kwargs.

    Values set to ``None`` will be dropped.
    """
    for k, v in kwargs.items():
        if v is not None:
            obj[k] = list(v) if hasattr(v, "__iter__") else [v]
        elif k in obj:
            obj.pop(k)
    return obj


@register.filter(name="verbose_name")
def do_verbose_name(obj, plural=False):
    """Return model's verbose name (singular or plural) or `obj` if it is a
    string (can act for default values)."""
    if isinstance(obj, str):
        return obj
    return obj._meta.verbose_name_plural if plural else obj._meta.verbose_name


@register.filter(name="edit_view")
def do_edit_view(obj):
    return "%s-edit" % obj.split("-")[0]


@register.filter(name="detail_view")
def do_detail_view(obj):
    return "%s-detail" % obj.split("-")[0]


@register.filter(name="is_checkbox")
def is_checkbox(field):
    """Return True if field is a checkbox."""
    return isinstance(field.widget, forms.CheckboxInput)


@register.filter(name="is_select")
def is_select(field):
    """Return True if field is a select."""
    return isinstance(field.widget, forms.Select)
