#!/usr/bin/env -S fontforge -script
# Script that patches a given font to include the Warp logo as a glyph in the font,
# using a unicode codepoint in the private use area.
import os
import sys

import fontforge
import psMat

# Default values match what we used when initially patching Roboto.
SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
DEFAULT_SVG_PATH = os.path.join(SCRIPT_DIR, "warp.svg")
DEFAULT_CODEPOINT = 0xE500  # Private Use Area
DEFAULT_GLYPH_NAME = "warpLogo"


def usage(exit_code: int) -> None:
    prog = os.path.basename(sys.argv[0])
    print(
        "\n".join(
            [
                f"Usage: {prog} <font.ttf> [--svg <icon.svg>] [--codepoint <hex>] [--name <glyph_name>]",
                "",
                "Patches the given font by importing an SVG icon as a new glyph.",
                "Defaults:",
                f"  --svg {DEFAULT_SVG_PATH}",
                f"  --codepoint 0x{DEFAULT_CODEPOINT:04X}",
                f"  --name {DEFAULT_GLYPH_NAME}",
            ]
        )
    )
    raise SystemExit(exit_code)


def parse_args(argv):
    if len(argv) < 2 or argv[1] in ("-h", "--help"):
        usage(0 if len(argv) >= 2 else 2)

    font_path = argv[1]
    svg_path = DEFAULT_SVG_PATH
    codepoint = DEFAULT_CODEPOINT
    glyph_name = DEFAULT_GLYPH_NAME

    i = 2
    while i < len(argv):
        arg = argv[i]

        if arg == "--svg":
            i += 1
            if i >= len(argv):
                usage(2)
            svg_path = argv[i]
        elif arg == "--codepoint":
            i += 1
            if i >= len(argv):
                usage(2)
            v = argv[i]
            # Accept 0xE500, E500, or decimal.
            codepoint = int(v, 16) if (v.startswith("0x") or any(c in v.lower() for c in "abcdef")) else int(v)
        elif arg == "--name":
            i += 1
            if i >= len(argv):
                usage(2)
            glyph_name = argv[i]
        else:
            print(f"Unknown argument: {arg}")
            usage(2)

        i += 1

    return font_path, svg_path, codepoint, glyph_name


def patch_font(font_path: str, svg_path: str, codepoint: int, glyph_name: str) -> None:
    if not os.path.exists(font_path):
        raise SystemExit(f"Font not found: {font_path}")

    if not os.path.exists(svg_path):
        raise SystemExit(f"SVG not found: {svg_path}")

    font = fontforge.open(font_path)

    # Create or replace the glyph.
    g = font.createChar(codepoint, glyph_name)
    g.clear()

    # Import the outlines.
    g.importOutlines(svg_path)

    # Clean up and make it robust for rasterization.
    g.removeOverlap()
    g.simplify()
    g.correctDirection()

    # Keep the logo from looking low: align the bottom of the imported outline to the baseline.
    # (This is the same adjustment we ended up applying after the initial patch.)
    xmin, ymin, xmax, ymax = g.boundingBox()
    if ymin != 0:
        g.transform(psMat.translate(0, -ymin))
        g.round()

    font.generate(font_path)
    font.close()


def main():
    font_path, svg_path, codepoint, glyph_name = parse_args(sys.argv)
    patch_font(font_path, svg_path, codepoint, glyph_name)
    print(f"Patched {font_path} with U+{codepoint:04X} ({glyph_name})")


if __name__ == "__main__":
    main()
