#!/usr/bin/env python3
# Copyright 2021 The Matrix.org Foundation C.I.C.
#
# Licensed 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 script takes a google fonts CSS URL, downloads the referenced fonts locally
# and spits out a modified CSS file which now points to those local fonts.
#
# Purely for the purposes of converting a website to use local font files instead of
# making requests to Google Fonts.

import re
import requests
import subprocess
import sys

# Pull the font filename to process and output directory to point at
if len(sys.argv) < 4:
    print(f"""
Error: Not enough arguments.

Usage: {sys.argv[0]} google_fonts_url font_directory css_font_path
* google fonts url: A URL leading to a google font css file (i.e https://fonts.googleapis.com/css?family=Inter)
* font directory: The location that font files will be downloaded to (i.e ../../fonts)
* font path: The directory the resulting CSS will be pointing to, relative to site root (i.e /unstable/css/fonts).
             This is where the browser will look for fonts.
""")
    sys.exit(1)

google_fonts_url = sys.argv[1]
font_output_dir = sys.argv[2]
css_font_path = sys.argv[3]

# Get font name
if google_fonts_url.count(":") > 1:
    # Account for font weights specified in the URL
    # (i.e https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i)
    url_match = re.match(r".*family=(.*):", google_fonts_url)
else:
    url_match = re.match(r".*family=(.*)", google_fonts_url)

if not url_match:
    print("Unable to extract font name, invalid google fonts URL:", google_fonts_url)
    print("URL should look something like: https://fonts.googleapis.com/css?family=Inter...")
    sys.exit(1)

font_name = url_match.group(1)

# Ensure font paths end with a trailing slash
if not font_output_dir.endswith("/"):
    font_output_dir += "/"
if not css_font_path.endswith("/"):
    css_font_path += "/"

# Download the css file and split by newline
resp = requests.get(
    google_fonts_url,
    # We need to set a believable user-agent, else google fonts won't give us
    # all of the font weights we requested for some reason
    headers={
        "User-Agent": "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0"
    }
)
if resp.status_code != 200:
    print("Failed to download:", google_fonts_url, resp.status_code)
    sys.exit(1)

original_contents = resp.text.split("\n")

# Download all referenced font files and write out new font file
new_css_file_lines = []

# Store metadata for helping give friendly names to each font file
font_lang = None
font_family = None
font_style = None
for line in original_contents:
    # Check if this line contains a font URL
    match = re.match(r".*url\((.*)\) format.*", line)
    if match:
        # Download the font file
        font_url = match.group(1)
        print("Downloading font:", font_url)

        resp = requests.get(font_url)
        if resp.status_code == 200:
            # Save the font file
            filename = "%s-%s-%s.woff2" % (
                font_family, font_lang, font_style
            )
            font_filepath = font_output_dir + filename
            with open(font_filepath, "wb") as f:
                print("Writing font file:", font_filepath)
                f.write(resp.content)

            # Replace google URL with local URL and allow the browser to load the
            # local font if it exists.
            line = re.sub(r"url\(.+?\)", f"local('{font_family}'), url({css_font_path + filename})", line)
        else:
            print("Warning: failed to download font file:", font_url)

    # Check for font metadata. If there is some, we'll note it down and use it to help
    # name font files when we write them out.
    # Makes for nicer font filenames than fvQtMwCp50KnMw2boKod... etc.
    font_lang_match = re.match(r"^/\* (.+) \*/$", line)
    if font_lang_match:
        font_lang = font_lang_match.group(1)
    font_family_match = re.match(r".*font-family: '(.+)';$", line)
    if font_family_match:
        font_family = font_family_match.group(1)
    font_style_match = re.match(r".*font-style: (.+);$", line)
    if font_style_match:
        font_style = font_style_match.group(1)

    # Append the potentially modified line to the new css file
    new_css_file_lines.append(line)

# Write out the new font css file
with open(font_name + ".css", "w") as f:
    new_css_file_contents = "\n".join(new_css_file_lines)
    f.write(new_css_file_contents)
