'''
PClinks Extension for Python-Markdown
======================================

Converts [[type:id]] to relative links.

Based on <https://Python-Markdown.github.io/extensions/wikilinks>.

Original code Copyright [Waylan Limberg](http://achinghead.com/).

License: [BSD](https://opensource.org/licenses/bsd-license.php)
'''

from markdown.extensions import Extension
from markdown.inlinepatterns import InlineProcessor
from uuid import UUID
import xml.etree.ElementTree as etree
from flask import url_for, render_template
from flask_login import current_user
from app.utils.unicode_names import normalize
from app.utils.filters.humanize import humanize
from app.models.poll import Poll
from app.models.topic import Topic
from app.models.user import Member
from app.models.attachment import Attachment


class PCLinkExtension(Extension):
    def __init__(self, **kwargs):
        self.config = {
            # 'base_url': ['/', 'String to append to beginning or URL.'],
            # 'end_url': ['/', 'String to append to end of URL.'],
            # 'html_class': ['pclink', 'CSS hook. Leave blank for none.'],
        }
        super().__init__(**kwargs)

    def extendMarkdown(self, md):
        self.md = md

        # append to end of inline patterns
        PCLINK_RE = r'<([a-z]+): ?([\w-]+)>'
        pclinkPattern = PCLinksInlineProcessor(PCLINK_RE, self.getConfigs())
        pclinkPattern.md = md
        md.inlinePatterns.register(pclinkPattern, 'pclink', 135)


class PCLinksInlineProcessor(InlineProcessor):
    def __init__(self, pattern, config):
        super().__init__(pattern)
        self.config = config
        self.handles = {
            'membre': handleUser, 'user': handleUser, 'u': handleUser,
            'sondage': handlePoll, 'poll': handlePoll,
            'topic': handleTopic, 't': handleTopic,
            'fichier': handleFile, 'file': handleFile, 'f': handleFile,
        }

    def handleMatch(self, m, data):
        link_type = m.group(1).strip()
        if link_type in self.handles:
            content_id = m.group(2).strip()
            a = self.handles[link_type](content_id, data)
        else:
            a = ''
        return a, m.start(0), m.end(0)


# pclinks are links defined as [[type:content_id]]
# To add a custom handle, create a function and add it to processor's handles
# A custom handle takes two arguments:
# - content_id: as defined
# - context: the block in which the link has been found
# It should return:
# - either a string, which will be html-escaped
# - either an xml.etree.ElementTree

def handlePoll(content_id, context):
    try:
        id = int(content_id)
    except ValueError:
        return "[ID de sondage invalide]"

    poll = Poll.query.get(content_id)

    if poll is None:
        return "[Sondage non trouvé]"

    html = render_template('widgets/poll.html', poll=poll)
    html = html.replace('\n', '')  # Needed to avoid lots of <br> due to etree
    return etree.fromstring(html)

def handleTopic(content_id, context):
    try:
        id = int(content_id)
    except ValueError:
        return "[ID de topic invalide]"

    topic = Topic.query.get(content_id)

    if topic is None:
        return "[Topic non trouvé]"

    a = etree.Element('a')
    a.text = topic.title
    a.set('href', url_for('forum_topic', f=topic.forum, page=(topic,1)))
    a.set('class', 'topic-link')

    return a

def handleUser(content_id, context):
    try:
        norm = normalize(content_id)
    except ValueError:
        return "[Nom d'utilisateur invalide]"

    member = Member.query.filter_by(norm=norm).first()

    if member is None:
        return "[Utilisateur non trouvé]"

    a = etree.Element('a')
    a.text = member.name
    a.set('href', url_for('user', username=member.norm))
    a.set('class', 'profile-link')

    return a

def handleFile(content_id, context):
    try:
        UUID(content_id)
    except ValueError:
        return "[ID de fichier invalide]"

    file = Attachment.query.get(content_id)

    if file is None:
        return "[Fichier non trouvé]"

    # Manage permissions
    # TODO: use Guest methods when implemented
    if current_user.is_authenticated:
        if not current_user.can_access_file(file):
            return "[Accès au fichier refusé]"
    else:
        if not file.comment.thread.is_default_accessible():
            return "[Accès au fichier refusé]"


    html = render_template('widgets/download_button.html', file=file)
    html = html.replace('\n', '')  # Needed to avoid lots of <br> due to etree
    return etree.fromstring(html)
