"""
utils.converter: Custom URL converters to match patterns in @app.route()

The Flask documentation is elusive on this topic. To add a new converter,
proceed as follows:

1. Define a new converter class.
2. Set the [regex] attribute to decide which portion of the URL will be
   considered for conversion (apparently the default is everything until next
   slash or end of string).
3. Define the to_python() and to_url() methods to actually convert.
4. Add the class to __all__ at the bottom of this file.
5. In app/__init__.py, add a dictionary entry to [app.url_map.converters].

For more information, see the Werkzeug documentation:
  <https://werkzeug.palletsprojects.com/en/0.15.x/routing/#custom-converters>
"""

from werkzeug.routing import BaseConverter, ValidationError
from app.models.forum import Forum
from app.models.topic import Topic
from slugify import slugify
import re
import sys

class ForumConverter(BaseConverter):

    # This regex will decide which portion of the URL is matched by the curtom
    # converter. By default, slashes are not included, so we must add them.
    regex = r'[a-z/]+'

    def to_python(self, url):
        url = '/' + url
        f = Forum.query.filter_by(url=url).first()
        if f is None:
            raise ValidationError(f"ForumConverter: no forum with url {url}")
        return f

    def to_url(self, forum):
        return forum.url[1:]

class TopicSlugConverter(BaseConverter):

    # Only catch integers followed by an optional slug string
    regex = r'(\d+)(?:-[\w-]*)?'

    def to_python(self, url):
        """Convert an URL pattern to a Python object, or raise an exception."""
        m = re.fullmatch(TopicSlugConverter.regex, url)
        if m is None:
            raise Exception(f"TopicSlugConverter: conversation failed")

        return Topic.query.get_or_404(int(m[1], 10))

    def to_url(self, topic):
        return f'{topic.id}-{slugify(topic.title)}'

# Export only the converter classes
__all__ = "ForumConverter TopicSlugConverter".split()
