"""
This module provides filters and other utilities for the Jinja2 templating engine.

Roundabout - git hosting for everyone <https://roundabout-host.com>
Copyright (C) 2023-2025 Roundabout developers <root@roundabout-host.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from app import app, _, n_
import flask
from datetime import datetime
import markdown
from markupsafe import Markup
from urllib.parse import urlencode


@app.template_global()
def modify_query(**new_values):
    args = flask.request.args.copy()

    for key, value in new_values.items():
        args[key] = value

    return f"{flask.request.path}?{urlencode(args)}"


@app.template_filter("split")
def split(value: str, separator=" ", maxsplit: int = -1):
    return value.split(separator, maxsplit)


@app.template_filter("splitlines")
def splitlines(value: str, keepends: bool = False):
    return value.splitlines(keepends=keepends)


@app.template_filter("lstrip")
def lstrip(value: str, characters=None):
    return value.lstrip(characters)


@app.template_filter("rstrip")
def rstrip(value: str, characters=None):
    return value.rstrip(characters)


@app.template_filter("strftime")
def strftime(value: datetime, syntax: str):
    # Split the strftime syntax into placeholders and literals.
    placeholders = {
        "%a", "%A", "%w", "%d", "%-d", "%b", "%B", "%m", "%-m", "%y", "%Y",
        "%H", "%-H", "%I", "%-I", "%p", "%M", "%-M", "%S", "%-S", "%f", "%z",
        "%Z", "%j", "%-j", "%U", "%W", "%c", "%x", "%X", "%%", "%G", "%u", "%V",
        "%-V", "%s", "%:z", "%e"
    }

    tokens = []
    i = 0
    length = len(syntax)
    while i < length:
        if syntax[i] == "%":
            if i+1 < length and syntax[i:i + 2] in placeholders:
                tokens.append(syntax[i:i + 2])
                i += 2
            elif i+1 < length and syntax[i:i + 3] in placeholders:
                tokens.append(syntax[i:i + 3])
                i += 3
            else:
                tokens.append(syntax[i])
                i += 1
        else:
            tokens.append(syntax[i])
            i += 1

    new_tokens = []

    for token in tokens:
        match token:
            case "%A":
                # Translate the full weekday name.
                weekday_number = value.weekday()
                weekday_names = [
                    _("Monday"),
                    _("Tuesday"),
                    _("Wednesday"),
                    _("Thursday"),
                    _("Friday"),
                    _("Saturday"),
                    _("Sunday")
                ]
                new_tokens.append(weekday_names[weekday_number])
            case "%a":
                # Translate the abbreviated weekday name.
                weekday_number = value.weekday()
                weekday_names = [
                    _("Mon"),
                    _("Tue"),
                    _("Wed"),
                    _("Thu"),
                    _("Fri"),
                    _("Sat"),
                    _("Sun")
                ]
                new_tokens.append(weekday_names[weekday_number])
            case "%B":
                # Translate the full month name.
                month_number = value.month
                month_names = [
                    _("January"),
                    _("February"),
                    _("March"),
                    _("April"),
                    _("May"),
                    _("June"),
                    _("July"),
                    _("August"),
                    _("September"),
                    _("October"),
                    _("November"),
                    _("December")
                ]
                new_tokens.append(month_names[month_number - 1])
            case "%b":
                # Translate the abbreviated month name.
                month_number = value.month
                month_names = [
                    _("Jan"),
                    _("Feb"),
                    _("Mar"),
                    _("Apr"),
                    _("May (short)"),
                    _("Jun"),
                    _("Jul"),
                    _("Aug"),
                    _("Sep"),
                    _("Oct"),
                    _("Nov"),
                    _("Dec")
                ]
                new_tokens.append(month_names[month_number - 1])
            case "%p":
                # Translate the AM/PM indicator.
                if value.hour < 12:
                    new_tokens.append(_("am"))
                else:
                    new_tokens.append(_("pm"))
            case _:
                new_tokens.append(token)

    syntax = "".join([value.strftime(token) if token in placeholders else token for token in new_tokens])

    return value.strftime(syntax)


@app.template_filter("unixtime")
def unixtime(value: datetime):
    return round(value.timestamp())


@app.template_filter("decode")
def decode(value: bytes, codec: str = "UTF-8", errors: str = "strict"):
    return value.decode(codec, errors)


@app.template_filter("markdown")
def parse_markdown(value: str):
    return Markup(markdown.make_html(markdown.tokenise(value)))


@app.template_filter("inline_markdown")
def parse_inline_markdown(value: str):
    return Markup(markdown.make_html(markdown.parse_line(value)))


@app.template_filter("parse_diff_location")
def parse_diff_location(value: str):
    header = value.split("@@")[1].strip()
    return [tuple(int(j) for j in i.lstrip("-+").split(",")) for i in header.split(" ")]


@app.template_filter("harvester_protection")
def harvester_protection(value):
    return "".join(f"&#x{ord(char):x};" for char in value)


@app.template_filter("sort")
def sort(value):
    return sorted(value)

@app.template_filter("profile_url")
def profile_url(value):
    if "@" in value:
        host = value.split("@")[1]
        user = value.split("@")[0]
        return f"http://{host}/users/{user}"
    else:
        return f"/{value}"
