import os
from datetime import date, timedelta
from operator import itemgetter

from django import template
from django.contrib.admin.templatetags.admin_list import _boolean_icon
from django.template.defaultfilters import linebreaksbr
from django.templatetags.static import static
from django.utils.dates import MONTHS
from django.utils.html import escape, format_html_join, format_html
from django.utils.safestring import SafeString, mark_safe
from django.utils.text import Truncator

from aemo.utils import format_d_m_Y, format_duree as _format_duree, format_adresse

register = template.Library()

IMAGE_EXTS = ['.jpg', '.jpeg', '.png', '.tif', '.tiff', '.gif']


@register.simple_tag
def relative_url(value, field_name, urlencode=None):
    url = '?{}={}'.format(field_name, value)
    if urlencode:
        querystring = urlencode.split('&')
        filtered_querystring = filter(lambda p: p.split('=')[0] != field_name, querystring)
        encoded_querystring = '&'.join(filtered_querystring)
        url = '{}&{}'.format(url, encoded_querystring)
    return url


@register.simple_tag
def get_verbose_field_name(instance, field_name):
    """
    Returns verbose_name for a field.
    """
    return instance._meta.get_field(field_name).verbose_name.capitalize()


@register.simple_tag
def get_field_value(instance, field_name):
    value = getattr(instance, field_name)
    if isinstance(value, str):
        return mark_safe(value)
    elif hasattr(value, 'all'):
        return mark_safe("<br>".join([str(v) for v in value.all()]))
    return value


@register.simple_tag
def help_tooltip(text):
    template = (
        '<span class="help" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" '
        'title="{text}"><img src="{icon}"></span>'
    )
    return format_html(template, text=linebreaksbr(escape(text)), icon=static("img/help.png"))


@register.filter
def boolean_icon(val):
    return _boolean_icon(val)


@register.filter
def get_item(obj, key):
    try:
        return obj.get(key) if obj is not None else obj
    except Exception:
        raise TypeError(f"Unable to get key '{key}' from obj '{obj}'")


@register.filter
def get_field(form, field_name):
    return form[field_name]


@register.filter
def as_field_group(ffield):
    # Waiting for Django 5.0
    if (ffield):
        return SafeString(" ".join([ffield.label_tag(), ffield.errors.as_ul(), str(ffield)]))
    return ''


@register.filter
def can_edit(obj, user):
    return obj.can_edit(user)


@register.filter
def can_delete(obj, user):
    return obj.can_delete(user)


@register.filter
def sigles_referents(suivi):
    """
    Affichage d'abord duo psy/educ, puis autres ressources. par ex: "Psy/Educ - Coach - ASE"
    """
    interventions = [{
        'nom': interv.intervenant.nom_prenom,
        'role': interv.role.nom,
        'sigle': interv.intervenant.sigle or interv.intervenant.nom
    } for interv in suivi.intervenant_set.all()
    ]
    template = '<span title="{nom}, {role}">{sigle}</span>'
    psyeduc = sorted([i for i in interventions if i['role'] in ['Psy', 'Educ']], key=itemgetter('sigle'))
    autres = sorted([i for i in interventions if i['role'] not in ['Psy', 'Educ']], key=itemgetter('sigle'))
    return SafeString(" - ".join([res for res in [
        "/".join([format_html(template, **i) for i in psyeduc]),
        " - ".join([format_html(template, **i)  for i in autres]),
    ] if res]))


@register.filter
def noms_referents_ope(suivi):
    return ' / '.join(ope.nom for ope in suivi.ope_referents)


@register.filter
def referents_pk_data(suivi):
    return ':'.join([str(ref.pk) for ref in suivi.intervenants.all()])


@register.filter
def join_qs(queryset, sep='/'):
    return sep.join([str(q) for q in queryset])


@register.filter
def in_parens(value):
    """Enclose value in parentheses only if it's not empty."""
    return '' if value in (None, '', []) else '({})'.format(value)


@register.filter
def etape_cellule(suivi, code_etape):
    """Produit le contenu d'une cellule du tableau de suivi des étapes."""
    def _css_class(date_suiv, default='next'):
        if date_suiv is None:
            # Ne devrait pas se produire, mais le cas échéant, éviter un crash.
            return default
        delta = date_suiv - date.today()
        if 19 > delta.days > 0:
            return 'urgent'
        if delta.days < 0:
            return 'depasse'
        return default

    etape = suivi.WORKFLOW[code_etape]
    etape_suiv = suivi.etape_suivante
    date_etape = etape.date(suivi)
    date_formatted = ''
    css_class = ''
    if date_etape:
        date_formatted = format_d_m_Y(date_etape)
        css_class = 'filled'
    elif etape_suiv and code_etape == etape_suiv.code:
        date_suiv = suivi.date_suivante()
        date_formatted = format_d_m_Y(date_suiv)
        css_class = _css_class(date_suiv)
        code_etape = etape_suiv.abrev
    else:
        # Certaines dates sont strictement liées au suivi
        date_etape = etape.delai_depuis(suivi, None)
        if date_etape:
            date_formatted = format_d_m_Y(date_etape)
            css_class = _css_class(date_etape, default='')
    return format_html(
        '<div title="{}:{}" class="{}" data-bs-toggle="tooltip">{}</div>',
        code_etape, date_formatted, css_class, etape.abrev
    )


@register.filter
def default_if_zero(duree):
    if isinstance(duree, timedelta):
        duree = _format_duree(duree)
    return '' if duree == '00:00' else duree


@register.filter
def strip_seconds(duree):
    if duree is None:
        return ''
    if str(duree).count(':') > 1:
        return ':'.join(format_duree(duree).split(':')[:2])


@register.filter
def format_duree(duree):
    return _format_duree(duree)


@register.filter
def strip_zeros(decimal):
    return str(decimal).rstrip('0').rstrip('.')


@register.filter(is_safe=True)
def strip_colon(txt):
    return txt.replace(' :', '')


@register.filter
def month_name(month_number):
    return MONTHS[month_number]


@register.filter(name='has_group')
def has_group(user, group_name):
    return user.groups.filter(name=group_name).exists()


@register.filter
def info_ope(ope):
    if ope:
        return format_html(
            '<span title="{}">{}</span>', ope.tel_prof, ope.nom_prenom,
        )
    else:
        return ''


@register.filter
def age_a(personne, date_):
    return personne.age_str(date_)


@register.filter
def is_passed(date_):
    return date_ < date.today()


@register.filter
def nom_prenom_abreg(person):
    return '{} {}.'.format(person.nom, person.prenom[0].upper() if person.prenom else '')


@register.simple_tag
def mes_totaux_mensuels(user, src, annee):
    return user.totaux_mensuels(src, annee)


@register.simple_tag
def mon_total_annuel(user, src, annee):
    return format_duree(user.total_annuel(src, annee))


@register.filter
def sigles_intervenants(prestation):
    return format_html_join(
        '/', '{}', ((i.sigle or i.nom,) for i in prestation.intervenants.all())
    )


@register.filter
def sigle_personne(pers):
    if pers is None:
        return '-'
    return format_html(
        '<span title="{}">{}</span>', pers.nom_prenom, pers.sigle or pers.nom
    )


@register.filter
def as_icon(fichier):
    if not fichier:
        return ''
    ext = os.path.splitext(fichier.name)[1].lower()
    if ext in IMAGE_EXTS:
        icon = 'image'
    elif ext in ('.xls', '.xlsx'):
        icon = 'xlsx'
    elif ext in ('.doc', '.docx'):
        icon = 'docx'
    elif ext == '.pdf':
        icon = 'pdf'
    else:
        icon = 'master'
    return format_html(
        '<a class="{klass}" href="{url}"><img class="ficon" src="{ficon}" alt="Télécharger"></a>',
        klass=icon, url=fichier.url, ficon=static(f"ficons/{icon}.svg")
    )


@register.simple_tag(takes_context=True)
def param_replace(context, **kwargs):
    d = context['request'].GET.copy()
    for k, v in kwargs.items():
        d[k] = v
    for k in [k for k, v in d.items() if not v]:
        del d[k]
    return d.urlencode()


@register.filter
def colorier_delai(value):
    if value <= 0:
        return "bg-danger-3"
    return ''


@register.filter
def benef_nom_adresse(obj):
    if obj:
        return '{} - {}'.format(obj.nom_prenom(),
                                format_adresse(obj.rue_actuelle, obj.npa_actuelle, obj.localite_actuelle))
    return 'Nouveau bénéficiaire'


@register.filter
def role_profession(contact):
    if contact.profession:
        return f"{contact.roles_str()} / {contact.profession}"
    return contact.roles_str()


@register.filter
def truncate_html_with_more(text, length):
    template = '''
        <div class="long hidden">{txt_long}</div>
        <div class="short">{txt_short}</div>
        {read_more}
    '''
    read_more = '<a class="read_more" href=".">Afficher la suite</a>'
    text_trunc = Truncator(text).words(int(length), html=True)
    return format_html(
        template,
        txt_long=mark_safe(text),
        txt_short=mark_safe(text_trunc),
        read_more=mark_safe(read_more) if text != text_trunc else '',
    )


@register.filter
def raw_or_html(value):
    if value and '</' in value:  # Considered as HTML
        return mark_safe(value)
    else:
        return linebreaksbr(escape(value))


@register.filter
def can_be_reactivated(obj, user):
    return obj.can_be_reactivated(user)


@register.filter
def archivable(famille, user):
    return famille.can_be_archived(user)
