"""Prepara as fontes das legendas a partir do repositorio oficial google/fonts.

Tres armadilhas resolvidas aqui:

1. Fontes variaveis. Boa parte das familias so existe como `Familia[wght].ttf`.
   O libass (que o ffmpeg usa pra queimar a legenda) ignora os eixos e desenha
   a instancia padrao - quase sempre Regular. Entao "Montserrat 900" sairia fino
   no video mesmo aparecendo grosso na previa. Aqui a gente fatia a variavel no
   peso pedido com o fontTools e grava um arquivo estatico.

2. Nome de familia ambiguo. O libass casa a fonte pelo NOME que esta dentro do
   arquivo, nao pelo nome do arquivo. Duas variantes com a mesma familia
   ("Poppins" Bold e Light) viram a mesma coisa pra ele. Por isso carimbamos um
   nome unico em cada arquivo e usamos esse nome nos dois lados: no @font-face
   do navegador e no estilo do ASS. Previa e video ficam identicos.

3. O nome do arquivo no repositorio muda. Quando o caminho chutado nao existe,
   lemos o METADATA.pb da pasta da familia e descobrimos o arquivo certo.
"""
import io
import json
import re
import sys
import urllib.request
from pathlib import Path

from fontTools.ttLib import TTFont
from fontTools.varLib import instancer

RAIZ = Path(__file__).resolve().parents[2]
OUT = RAIZ / "static" / "fonts"
OUT.mkdir(parents=True, exist_ok=True)
BASE = "https://raw.githubusercontent.com/google/fonts/main/"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"

# apelido -> (pasta da familia, arquivo preferido, eixos p/ fatiar, nome carimbado)
WANT = {
    # --- sem serifa, pesadas ---
    "anton":        ("ofl/anton", "Anton-Regular.ttf", None, "Anton"),
    "archivo":      ("ofl/archivoblack", "ArchivoBlack-Regular.ttf", None, "Archivo Black"),
    "montblack":    ("ofl/montserrat", "Montserrat[wght].ttf", {"wght": 900}, "Montserrat Black"),
    "figtree":      ("ofl/figtree", "Figtree[wght].ttf", {"wght": 900}, "Figtree Black"),
    "outfit":       ("ofl/outfit", "Outfit[wght].ttf", {"wght": 900}, "Outfit Black"),
    "manrope":      ("ofl/manrope", "Manrope[wght].ttf", {"wght": 800}, "Manrope Extrabold"),
    "sora":         ("ofl/sora", "Sora[wght].ttf", {"wght": 800}, "Sora Extrabold"),
    "syne":         ("ofl/syne", "Syne[wght].ttf", {"wght": 800}, "Syne Extrabold"),
    "chivo":        ("ofl/chivo", "Chivo[wght].ttf", {"wght": 900}, "Chivo Black"),
    "epilogue":     ("ofl/epilogue", "Epilogue[wght].ttf", {"wght": 900}, "Epilogue Black"),
    "jakarta":      ("ofl/plusjakartasans", "PlusJakartaSans[wght].ttf", {"wght": 800}, "Jakarta Extrabold"),
    "gabarito":     ("ofl/gabarito", "Gabarito[wght].ttf", {"wght": 900}, "Gabarito Black"),
    "lexend":       ("ofl/lexend", "Lexend[wght].ttf", {"wght": 800}, "Lexend Extrabold"),
    "spartan":      ("ofl/leaguespartan", "LeagueSpartan[wght].ttf", {"wght": 800}, "Spartan Extrabold"),
    "nunito":       ("ofl/nunito", "Nunito[wght].ttf", {"wght": 900}, "Nunito Black"),
    "raleway":      ("ofl/raleway", "Raleway[wght].ttf", {"wght": 900}, "Raleway Black"),
    "rubik":        ("ofl/rubik", "Rubik[wght].ttf", {"wght": 800}, "Rubik Extrabold"),
    "onest":        ("ofl/onest", "Onest[wght].ttf", {"wght": 800}, "Onest Extrabold"),
    "schibsted":    ("ofl/schibstedgrotesk", "SchibstedGrotesk[wght].ttf", {"wght": 800}, "Schibsted Extrabold"),
    "spacegrotesk": ("ofl/spacegrotesk", "SpaceGrotesk[wght].ttf", {"wght": 700}, "Space Grotesk Bold"),
    "bricolage":    ("ofl/bricolagegrotesque", "BricolageGrotesque[opsz,wdth,wght].ttf", {"wght": 800}, "Bricolage Extrabold"),
    "unbounded":    ("ofl/unbounded", "Unbounded[wght].ttf", {"wght": 800}, "Unbounded Extrabold"),
    "anybody":      ("ofl/anybody", "Anybody[wdth,wght].ttf", {"wght": 800}, "Anybody Extrabold"),

    # --- sem serifa, leves (para a linha de cima dos estilos de duas alturas) ---
    "montlight":    ("ofl/montserrat", "Montserrat[wght].ttf", {"wght": 300}, "Montserrat Light"),
    "poppins":      ("ofl/poppins", "Poppins-Bold.ttf", None, "Poppins Bold"),
    "poppinslight": ("ofl/poppins", "Poppins-Light.ttf", None, "Poppins Light"),
    "interbold":    ("ofl/inter", "Inter[opsz,wght].ttf", {"wght": 800, "opsz": 32}, "Inter Extrabold"),
    "inter":        ("ofl/inter", "Inter[opsz,wght].ttf", {"wght": 500, "opsz": 18}, "Inter Medium"),
    "jakartalight": ("ofl/plusjakartasans", "PlusJakartaSans[wght].ttf", {"wght": 300}, "Jakarta Light"),
    "ralewaylight": ("ofl/raleway", "Raleway[wght].ttf", {"wght": 300}, "Raleway Light"),
    "outfitlight":  ("ofl/outfit", "Outfit[wght].ttf", {"wght": 300}, "Outfit Light"),
    "quicksand":    ("ofl/quicksand", "Quicksand[wght].ttf", {"wght": 600}, "Quicksand Semibold"),
    "fredoka":      ("ofl/fredoka", "Fredoka[wdth,wght].ttf", {"wght": 600}, "Fredoka Semibold"),

    # --- condensadas ---
    "bebas":        ("ofl/bebasneue", "BebasNeue-Regular.ttf", None, "Bebas Neue"),
    "oswald":       ("ofl/oswald", "Oswald[wght].ttf", {"wght": 700}, "Oswald Bold"),
    "antonio":      ("ofl/antonio", "Antonio[wght].ttf", {"wght": 700}, "Antonio Bold"),
    "teko":         ("ofl/teko", "Teko[wght].ttf", {"wght": 700}, "Teko Bold"),
    "barlowcond":   ("ofl/barlowcondensed", "BarlowCondensed-Bold.ttf", None, "Barlow Condensed Bold"),
    "bigshoulders": ("ofl/bigshouldersdisplay", "BigShouldersDisplay[wght].ttf", {"wght": 800}, "Big Shoulders Extrabold"),
    "kanit":        ("ofl/kanit", "Kanit-Bold.ttf", None, "Kanit Bold"),

    # --- serifadas ---
    "playfair":     ("ofl/playfairdisplay", "PlayfairDisplay[wght].ttf", {"wght": 700}, "Playfair Bold"),
    "playfairit":   ("ofl/playfairdisplay", "PlayfairDisplay-Italic[wght].ttf", {"wght": 500}, "Playfair Italic"),
    "dmserif":      ("ofl/dmserifdisplay", "DMSerifDisplay-Regular.ttf", None, "DM Serif Display"),
    "instrument":   ("ofl/instrumentserif", "InstrumentSerif-Regular.ttf", None, "Instrument Serif"),
    "baskerville":  ("ofl/librebaskerville", "LibreBaskerville-Bold.ttf", {"wght": 700}, "Baskerville Bold"),
    "loraital":     ("ofl/lora", "Lora-Italic[wght].ttf", {"wght": 600}, "Lora Italic"),
    "cormorant":    ("ofl/cormorantgaramond", "CormorantGaramond[wght].ttf", {"wght": 700}, "Cormorant Bold"),
    "bodoni":       ("ofl/bodonimoda", "BodoniModa[opsz,wght].ttf", {"wght": 700}, "Bodoni Bold"),
    "fraunces":     ("ofl/fraunces", "Fraunces[SOFT,WONK,opsz,wght].ttf", {"wght": 700}, "Fraunces Bold"),
    "abril":        ("ofl/abrilfatface", "AbrilFatface-Regular.ttf", None, "Abril Fatface"),
    "alfaslab":     ("ofl/alfaslabone", "AlfaSlabOne-Regular.ttf", None, "Alfa Slab One"),

    # --- decorativas e divertidas ---
    "bungee":       ("ofl/bungee", "Bungee-Regular.ttf", None, "Bungee"),
    "passion":      ("ofl/passionone", "PassionOne-Bold.ttf", None, "Passion One"),
    "titan":        ("ofl/titanone", "TitanOne-Regular.ttf", None, "Titan One"),
    "bowlby":       ("ofl/bowlbyone", "BowlbyOne-Regular.ttf", None, "Bowlby One"),
    "righteous":    ("ofl/righteous", "Righteous-Regular.ttf", None, "Righteous"),
    "bakbak":       ("ofl/bakbakone", "BakbakOne-Regular.ttf", None, "Bakbak One"),
    "michroma":     ("ofl/michroma", "Michroma-Regular.ttf", None, "Michroma"),
    "orbitron":     ("ofl/orbitron", "Orbitron[wght].ttf", {"wght": 800}, "Orbitron Extrabold"),

    # --- manuscritas ---
    "caveat":       ("ofl/caveat", "Caveat[wght].ttf", {"wght": 700}, "Caveat Bold"),
    "marker":       ("apache/permanentmarker", "PermanentMarker-Regular.ttf", None, "Permanent Marker"),
    "kalam":        ("ofl/kalam", "Kalam-Bold.ttf", None, "Kalam Bold"),
    "amatic":       ("ofl/amaticsc", "AmaticSC-Bold.ttf", None, "Amatic Bold"),
    "pacifico":     ("ofl/pacifico", "Pacifico-Regular.ttf", None, "Pacifico"),
    "lobster":      ("ofl/lobster", "Lobster-Regular.ttf", None, "Lobster"),

    # --- monoespacada ---
    "mono":         ("ofl/jetbrainsmono", "JetBrainsMono[wght].ttf", {"wght": 700}, "JetBrains Bold"),
    "spacemono":    ("ofl/spacemono", "SpaceMono-Bold.ttf", None, "Space Mono Bold"),
}


def fetch(url: str) -> bytes:
    return urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": UA}), timeout=90).read()


def files_in_metadata(folder: str) -> list:
    """Nomes de arquivo declarados no METADATA.pb da familia."""
    try:
        txt = fetch(f"{BASE}{folder}/METADATA.pb").decode("utf-8", "replace")
    except Exception:  # noqa: BLE001
        return []
    return re.findall(r'filename:\s*"([^"]+\.ttf)"', txt)


def download(folder: str, preferred: str, italic: bool) -> bytes:
    """Tenta o arquivo preferido; se nao existir, pergunta ao METADATA.pb."""
    candidates = [preferred]
    for name in files_in_metadata(folder):
        if name not in candidates and (("Italic" in name) == italic):
            candidates.append(name)
    last = None
    for name in candidates:
        try:
            data = fetch(f"{BASE}{folder}/{name}")
        except Exception as e:  # noqa: BLE001
            last = e
            continue
        if data[:4] in (b"\x00\x01\x00\x00", b"true", b"OTTO"):
            return data
        last = RuntimeError("não é TrueType")
    raise last or RuntimeError("nenhum arquivo servia")


def stamp_name(font: TTFont, family: str):
    """Deixa um unico nome de familia no arquivo, em todas as plataformas."""
    name = font["name"]
    keep = {1: family, 2: "Regular", 3: f"Legendei:{family}", 4: family, 6: family.replace(" ", "")}
    name.names = [r for r in name.names if r.nameID in keep or r.nameID in (0, 5, 7, 8, 9, 13, 14)]
    for nid, val in keep.items():
        name.setName(val, nid, 3, 1, 0x409)
        name.setName(val, nid, 1, 0, 0)
    # nameID 16/17 (familia tipografica) sobrepoem o 1/2 e reintroduzem a ambiguidade
    name.names = [r for r in name.names if r.nameID not in (16, 17, 21, 22)]
    # o libass tambem olha os bits de estilo; deixamos tudo como "Regular"
    font["OS/2"].fsSelection = (font["OS/2"].fsSelection & ~0b100001) | 0b1000000
    font["head"].macStyle = 0


result, fail = {}, []
for key, (folder, preferred, axes, family) in WANT.items():
    dst = OUT / f"{key}.ttf"
    try:
        if not dst.exists() or dst.stat().st_size < 5000:
            raw = download(folder, preferred, "Italic" in preferred)
            font = TTFont(io.BytesIO(raw))
            if "fvar" in font:
                # trava TODOS os eixos: sobrar um deixa a fonte variavel e o
                # libass volta a desenhar a instancia padrao (peso errado)
                axes = axes or {}
                pin = {a.axisTag: axes.get(a.axisTag, a.defaultValue) for a in font["fvar"].axes}
                font = instancer.instantiateVariableFont(font, pin, updateFontNames=False)
            stamp_name(font, family)
            font.save(dst)
        f = TTFont(dst, lazy=True)
        got = f["name"].getDebugName(1)
        var = "fvar" in f
        f.close()
        if got != family:
            raise RuntimeError(f"nome saiu como '{got}', esperava '{family}'")
        result[key] = {"file": f"{key}.ttf", "family": family, "kb": dst.stat().st_size // 1024, "variable": var}
    except Exception as e:  # noqa: BLE001
        fail.append(f"{key}: {e}")
        dst.unlink(missing_ok=True)

(RAIZ / "app" / "fontes.json").write_text(json.dumps(result, ensure_ascii=False, indent=2), "utf-8")
for k, v in sorted(result.items()):
    print(f"  {k:<13} '{v['family']}' {v['kb']} KB{'  AINDA VARIAVEL!' if v['variable'] else ''}")
print(f"\n{len(result)} fontes prontas")
if fail:
    print("Falharam (os estilos que usam essas ficam de fora):")
    for f in fail:
        print("  ", f)
