from datetime import date, datetime, timedelta
import calendar
from string import ascii_uppercase as auc
from urllib.parse import urlparse
from django.utils.formats import localize
from django.utils import dates

import emoji
from dateutil.relativedelta import relativedelta
from django import template
from django.template.defaultfilters import stringfilter
from django.templatetags.static import static
from django.urls import reverse_lazy
from django.utils.html import strip_tags
from django.utils.safestring import mark_safe

register = template.Library()


@register.filter
def is_facebook_url(url):
    if url is None:
        return False
    obj = urlparse(url)
    if obj and obj.hostname:
        return obj.hostname.endswith("facebook.com")
    else:
        return False


@register.filter
def hostname(url):
    if url is None:
        return None
    obj = urlparse(url)
    if obj is None:
        return url
    hostname = obj.hostname
    if hostname:
        return mark_safe(hostname)
    else:
        return url


@register.filter
def add_de(txt):
    return ("d'" if txt[0].lower() in ["a", "e", "i", "o", "u", "y"] else "de ") + txt


@register.filter
def week(d):
    return d.isocalendar()[1]


@register.filter
def weekyear(d):
    return d.isocalendar()[0]


@register.filter
def not_before_first(d):
    return d >= datetime.now().date() - relativedelta(years=1)


@register.filter
def not_after_last(d):
    return d <= datetime.now().date() + relativedelta(years=1)


@register.filter
def shift_day(d, shift):
    return d + timedelta(days=shift)


@register.filter
def first_day_of_this_week(d):
    return date.fromisocalendar(d.year, week(d), 1)


@register.filter
def last_day_of_this_week(d):
    return date.fromisocalendar(d.year, week(d), 7)


@register.filter
def calendar_classes(d, fixed_style):
    result = ""
    if not fixed_style:
        if d.is_in_past():
            result += " past"
        if d.is_today():
            result += " today"
    if not d.on_requested_interval:
        result += " other_month"
    return result


@register.filter
def url_day(d, category=None):
    if category:
        return reverse_lazy(
            "day_view_category",
            kwargs={
                "year": d.year,
                "month": d.month,
                "day": d.day,
                "cat": category.slug,
            },
        )
    else:
        return reverse_lazy(
            "day_view", kwargs={"year": d.year, "month": d.month, "day": d.day}
        )


@register.simple_tag
def picto_from_name(name, datatooltip=""):
    result = (
        '<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">'
        + '<use href="'
        + static("images/feather-sprite.svg")
        + "#"
        + name
        + '" />'
        + "</svg>"
    )
    if datatooltip != "":
        result = '<span data-tooltip="' + datatooltip + '">' + result + "</span>"

    return mark_safe(result)


@register.filter
def int_to_abc(d):
    return auc[int(d)]


@register.filter(is_safe=True)
@stringfilter
def truncatechars_middle(value, arg):
    try:
        ln = int(arg)
    except ValueError:
        return value
    if len(value) <= ln:
        return value
    else:
        return "{}...{}".format(value[: ln // 2], value[-((ln + 1) // 2) :])


@register.filter
def frdate(d):
    return ("!" + d).replace(" 1 ", " 1er ").replace("!1 ", "!1er ")[1:]


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)


@register.filter
def remove_id_prefix(value):
    return int(value.replace("id_", ""))


@register.filter
def tocoords(c):
    return str(c.coords[1]) + ", " + str(c.coords[0])


@register.filter
def index(indexable, i):
    return indexable[i]


@register.filter
def is_string(val):
    return isinstance(val, str)


@register.filter
def html_vide(val):
    return len(strip_tags(val).replace("&nbsp;", "").strip()) == 0


@register.filter
def no_emoji(text):
    return emoji.replace_emoji(text, replace="")


@register.simple_tag
def navigation_links(filter, category, calendar, current_view):
    extra = "?" + filter.get_url()

    result = ""

    extra_path = "" if category is None else "_category"

    if not calendar.today_in_calendar():
        if current_view == "upcoming":
            params = {}
            if category:
                params["cat"] = category.slug
            params["year"] = calendar.firstdate.year
            params["week"] = calendar.firstdate.isocalendar()[1]
            result += (
                '<li><a href="'
                + reverse_lazy("week_view" + extra_path, kwargs=params)
                + extra
                + '">semaine du '
                + localize(calendar.firstdate)
                + "</a></li>"
            )

        if current_view != "month":
            params = {}
            if category:
                params["cat"] = category.slug

            days = [calendar.firstdate]
            if calendar.firstdate.month != calendar.lastdate.month:
                days.append(calendar.lastdate)
            for d in days:
                params["year"] = d.year
                params["month"] = d.month
                result += (
                    '<li><a href="'
                    + reverse_lazy("month_view" + extra_path, kwargs=params)
                    + extra
                    + '">'
                    + dates.MONTHS[d.month]
                    + " "
                    + str(d.year)
                    + "</a></li>"
                )

    kwargs = {}
    if category:
        kwargs["cat"] = category.slug

    for t in [
        ("aujourdhui", "aujourd'hui"),
        ("a_venir", "ces jours-ci"),
        ("cette_semaine", "cette semaine"),
        ("ce_mois_ci", "ce mois-ci"),
    ]:
        result += (
            '<li><a href="'
            + reverse_lazy(t[0] + extra_path, kwargs=kwargs)
            + extra
            + '">'
            + t[1]
            + "</a></li>"
        )

    return mark_safe(result)


@register.filter
def per_day(nb, month):
    weekday, number_of_days = calendar.monthrange(month.year, month.month)
    return "%.1f" % (nb / number_of_days)
