#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
This is a collection of simple in-page callable tools for pelican.
To use a function, use the following syntax in your markdown:
` spu:command_name("arg1", "arg2", "arg3") `

In HTML, you would do:
<code> spu:command_name("arg1", "arg2") </code>

command_name must match a respective spu_cmd_* command in python.
"""
try:
    from pelican.plugins import signals
except ImportError:
    from pelican import signals
import pelican.contents
import requests
import urllib.parse
import fnmatch
import re

# List of subdomains deemed safe for spu:fetch()
SPU_FETCH_SAFE_DOMAINS = ("*.apache.org",)

REQUESTS_TIMEOUT = 5 # timeout for requests calls

def spu_cmd_fetch(args: list):
    """Fetches an external URL and put the content where the call was made"""
    url = args[0]
    url_parsed = urllib.parse.urlparse(url)
    is_safe = any(fnmatch.fnmatch(url_parsed.netloc, pattern) for pattern in SPU_FETCH_SAFE_DOMAINS)
    if is_safe:
        print("Fetching external resource " + url)
        return requests.get(url, timeout=REQUESTS_TIMEOUT).text
    else:
        print("Not fetching unsafe external resource " + url)
        return ""


def spu_sub(call):
    my_functions = {k: v for k, v in globals().items() if callable(v) and k.startswith("spu_cmd_")}
    cmd = call.group(1)
    args = [x[1] for x in re.findall(r"(['\"]?)(.*?)\1(?:,\s*)?", call.group(2)) if x[1]]
    fnc = "spu_cmd_" + cmd
    if fnc in my_functions:
        return my_functions[fnc](args)
    return ""


def spu_parse(instance: pelican.contents.Page):
    if instance._content is not None:  # pylint: disable=protected-access
        instance._content = re.sub( # pylint: disable=protected-access
            r"<code>\s*spu:([_a-z]+)\(((?:(['\"]?)(.*?)\3(?:,\s*)?)*)\s*?\)\s*<\/code>",
            spu_sub,
            instance._content, # pylint: disable=protected-access
            flags=re.UNICODE,
        )


def register():
    print("Simple Pelican Utils registered.")
    signals.content_object_init.connect(spu_parse)
