#!/usr/bin/env python3
"""
Gera a família de SVGs vetoriais da logo Bera v2.1 (wordmark em Versos, sigil diamante).

v2.1: 2026-09-04: a fonte institucional passa a ser a Versos (Fabio Haag Type, licença
Individual). Wordmark "bera" em Versos 700 com tracking −0,02em, decisão do Bera por clique
(specimen em ~/Workspaces/portfolio/design-system/specimen/). O diamante mantém a geometria
da v2.0: losango ortogonal 1:1, lado = 0,2814 da cap-height, centro no topo do "b" (cap-height),
gap de 0,075em após o "a". Cor por tema: color-dark dourado #E5B748, color-light terracota #B4441F (decisão de 2026-08-19, registrada em 2026-09-04).

Diferença de engenharia vs v2.0 (build_bera_diamond_svgs.py): os paths das letras são
extraídos da fonte em tempo de execução (fontTools), porque a Versos é licenciada e não pode
ser redistribuída dentro do repo. Aponte a fonte com --font ou VERSOS_TTF; o padrão procura
Versos-Bold.ttf na pasta da compra (iCloud) e em ~/Library/Fonts.

Saída (10 arquivos: os 9 da v2.0 com os mesmos nomes, mais o favicon):
  bera-lockup-{white,black}.svg           primários mono
  bera-lockup-color-{light,dark}.svg      color (diamante terracota / dourado)
  bera-symbol-{white,black}.svg           monograma b◆ mono
  bera-symbol-color-{light,dark}.svg      monograma b◆ color
  bera-diamond.svg                        diamante isolado em currentColor
  bera-favicon.svg                        favicon canônico b◆ tema-aware (claro: tinta + terracota; escuro: papel + dourado)
"""
import argparse
import os
from pathlib import Path

from fontTools.ttLib import TTFont
from fontTools.pens.svgPathPen import SVGPathPen

REPO = Path(__file__).resolve().parent.parent
OUT_DIR_DEFAULT = REPO / "assets" / "logo"
FONT_CANDIDATES = [
    Path(os.environ.get("VERSOS_TTF", "")),
    Path.home() / "Library/Mobile Documents/com~apple~CloudDocs/bera-assets/Fonte Versos/Desktop/TTF/Versos-Bold.ttf",
    Path.home() / "Library/Fonts/Versos-Bold.ttf",
]

# ---------- decisões v2.1 (Bera, 2026-09-04) ----------
WORD = "bera"
WEIGHT = 700                 # peso do wordmark
TRACKING_EM = -0.02          # tracking do wordmark
GAP_EM = 0.075               # gap horizontal entre o "a" e o diamante (herdado da v2.0)
DIAMOND_CAP_FRACTION = 0.2814  # lado do diamante em fração da cap-height (v2.0)
SYMBOL_RISE = 983.40 / 1490.0  # centro do diamante no monograma, em fração da cap (v1/v2 mantido)
PAD_H_EM, PAD_V_EM, SYM_PAD_EM = 0.04, 0.06, 0.20

INK = "#0A0A0A"
PAPER = "#FAFAFA"
GOLD = "#E5B748"        # referência do tema escuro
TERRA_DEEP = "#B4441F"  # referência do tema claro (terracota; o violeta saiu na v2.1)


def find_font(explicit: str | None) -> Path:
    cands = ([Path(explicit)] if explicit else []) + FONT_CANDIDATES
    for c in cands:
        if c and c.is_file():
            return c
    raise SystemExit("Versos-Bold.ttf não encontrada: passe --font ou defina VERSOS_TTF")


def kern(gpos, a: str, b: str) -> int:
    """Kerning horizontal (XAdvance) do par a→b pela feature 'kern' (PairPos formato 1 e 2)."""
    lookups = set()
    for fr in gpos.FeatureList.FeatureRecord:
        if fr.FeatureTag == "kern":
            lookups.update(fr.Feature.LookupListIndex)
    for li in sorted(lookups):
        for st in gpos.LookupList.Lookup[li].SubTable:
            st = getattr(st, "ExtSubTable", st)
            if st.LookupType != 2 or a not in st.Coverage.glyphs:
                continue
            if st.Format == 1:
                for pvr in st.PairSet[st.Coverage.glyphs.index(a)].PairValueRecord:
                    if pvr.SecondGlyph == b and pvr.Value1 is not None:
                        return getattr(pvr.Value1, "XAdvance", 0) or 0
            elif st.Format == 2:
                c1 = st.ClassDef1.classDefs.get(a, 0)
                c2 = st.ClassDef2.classDefs.get(b, 0)
                v = st.Class1Record[c1].Class2Record[c2].Value1
                x = (getattr(v, "XAdvance", 0) or 0) if v is not None else 0
                if x:
                    return x
    return 0


def load_letters(font_path: Path):
    """Devolve (upm, cap, [(x, path_d, advance)], text_end) para WORD, com kerning e tracking."""
    t = TTFont(font_path)
    upm = t["head"].unitsPerEm
    cap = t["OS/2"].sCapHeight
    weight = t["OS/2"].usWeightClass
    if weight != WEIGHT:
        raise SystemExit(f"a fonte {font_path.name} tem peso {weight}; o wordmark v2.1 pede {WEIGHT}")
    cmap = t.getBestCmap()
    gs = t.getGlyphSet()
    names = [cmap[ord(ch)] for ch in WORD]
    tracking = TRACKING_EM * upm
    letters, x = [], 0.0
    for i, g in enumerate(names):
        pen = SVGPathPen(gs)
        gs[g].draw(pen)
        adv = t["hmtx"][g][0]
        letters.append((x, pen.getCommands(), adv))
        x += adv + tracking
        if i + 1 < len(names) and "GPOS" in t:
            x += kern(t["GPOS"].table, g, names[i + 1])
    text_end = letters[-1][0] + letters[-1][2]  # sem tracking depois da última letra
    return upm, cap, letters, text_end


def diamond_d(cx: float, cy: float, half: float) -> str:
    """Losango ortogonal 1:1 (coordenadas Y-up, absolutas)."""
    return (f"M {cx:.2f} {cy + half:.2f} L {cx + half:.2f} {cy:.2f} "
            f"L {cx:.2f} {cy - half:.2f} L {cx - half:.2f} {cy:.2f} Z")


class Geometry:
    def __init__(self, font_path: Path):
        self.upm, self.cap, self.letters, self.text_end = load_letters(font_path)
        u = self.upm
        self.pad_h, self.pad_v, self.sym_pad = PAD_H_EM * u, PAD_V_EM * u, SYM_PAD_EM * u
        self.size = self.cap * DIAMOND_CAP_FRACTION
        self.half = self.size / 2
        self.lockup_cx = self.text_end + GAP_EM * u + self.half
        self.lockup_cy = float(self.cap)                      # centro exatamente na cap-height
        self.b_advance = self.letters[0][2]
        self.sym_cx = self.b_advance + GAP_EM * u + self.half
        self.sym_cy = self.cap * SYMBOL_RISE
        self.b_glyph = self.letters[0][1]

    def letters_group(self, color: str) -> str:
        return "\n".join(
            f'  <path transform="translate({x:.2f} 0)" fill="{color}" d="{d}"/>'
            for x, d, _ in self.letters
        )

    def lockup(self, *, text_color: str, diamond_color: str, title: str) -> str:
        top = max(max(self.cap, self.lockup_cy + self.half), self._ink_top()) + self.pad_v
        bottom = self._ink_bottom() - self.pad_v
        view_w = self.lockup_cx + self.half + self.pad_h * 2
        view_h = top - bottom
        return f'''<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="{-self.pad_h:.2f} {-top:.2f} {view_w:.2f} {view_h:.2f}"
     role="img" aria-label="{title}">
  <title>{title}</title>
  <g transform="scale(1 -1)">
{self.letters_group(text_color)}
    <path fill="{diamond_color}" d="{diamond_d(self.lockup_cx, self.lockup_cy, self.half)}"/>
  </g>
</svg>
'''

    def _symbol_frame(self):
        """Quadro do monograma (lado, deslocamento do b, baseline e path do diamante), compartilhado por symbol e favicon."""
        content_w = self.sym_cx + self.half
        content_h = self._ink_top() + self.pad_v
        side = max(content_w, content_h) + self.sym_pad * 2
        off_x = (side - content_w) / 2
        off_y = (side - content_h) / 2
        baseline_y = side - off_y
        d = diamond_d(off_x + self.sym_cx, off_y + self.sym_cy, self.half)
        return side, off_x, baseline_y, d

    def symbol(self, *, text_color: str, diamond_color: str, title: str) -> str:
        side, off_x, baseline_y, d = self._symbol_frame()
        return f'''<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 {side:.2f} {side:.2f}"
     role="img" aria-label="{title}">
  <title>{title}</title>
  <g transform="translate(0 {baseline_y:.2f}) scale(1 -1)">
    <path transform="translate({off_x:.2f} 0)" fill="{text_color}" d="{self.b_glyph}"/>
    <path fill="{diamond_color}" d="{d}"/>
  </g>
</svg>
'''

    def favicon(self, *, title: str) -> str:
        """Favicon canônico (site/favicon.svg e réplicas): monograma b◆ com cores por prefers-color-scheme.
        Claro: tinta + terracota profunda; escuro: papel + dourado. Mesma geometria do symbol."""
        side, off_x, baseline_y, d = self._symbol_frame()
        return f'''<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 {side:.2f} {side:.2f}"
     role="img" aria-label="{title}">
  <title>{title}</title>
  <style>
    .b {{ fill: {INK}; }} .d {{ fill: {TERRA_DEEP}; }}
    @media (prefers-color-scheme: dark) {{ .b {{ fill: {PAPER}; }} .d {{ fill: {GOLD}; }} }}
  </style>
  <g transform="translate(0 {baseline_y:.2f}) scale(1 -1)">
    <path class="b" transform="translate({off_x:.2f} 0)" d="{self.b_glyph}"/>
    <path class="d" d="{d}"/>
  </g>
</svg>
'''

    # limites de tinta das letras (o ascender do b e o overshoot das curvas passam da cap e da baseline)
    def _ink_top(self) -> float:
        return max(self._bbox()[3], self.cap)

    def _ink_bottom(self) -> float:
        return min(self._bbox()[1], 0.0)

    def _bbox(self):
        if not hasattr(self, "_bb"):
            import re
            ys, xs = [], []
            for x0, d, _ in self.letters:
                for mx, my in re.findall(r"(-?\d+\.?\d*) (-?\d+\.?\d*)", d):
                    xs.append(float(mx) + x0); ys.append(float(my))
            self._bb = (min(xs), min(ys), max(xs), max(ys))
        return self._bb


def diamond_only(*, title: str) -> str:
    size, pad = 100, 12
    side = size + pad * 2
    c = side / 2
    return f'''<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 {side} {side}"
     role="img" aria-label="{title}">
  <title>{title}</title>
  <g transform="translate(0 {side}) scale(1 -1)">
    <path fill="currentColor" d="{diamond_d(c, c, size / 2)}"/>
  </g>
</svg>
'''


def build_files(g: Geometry) -> dict[str, str]:
    return {
        "bera-lockup-white.svg": g.lockup(text_color=PAPER, diamond_color=PAPER,
            title="Bera: lockup branco (uso sobre fundos escuros)"),
        "bera-lockup-black.svg": g.lockup(text_color=INK, diamond_color=INK,
            title="Bera: lockup preto (uso sobre fundos claros)"),
        "bera-lockup-color-light.svg": g.lockup(text_color=INK, diamond_color=TERRA_DEEP,
            title="Bera: lockup color (texto preto + diamante terracota, uso em fundo claro)"),
        "bera-lockup-color-dark.svg": g.lockup(text_color=PAPER, diamond_color=GOLD,
            title="Bera: lockup color (texto branco + diamante dourado, uso em fundo escuro)"),
        "bera-symbol-white.svg": g.symbol(text_color=PAPER, diamond_color=PAPER,
            title="Bera: symbol b◆ branco (uso sobre fundos escuros)"),
        "bera-symbol-black.svg": g.symbol(text_color=INK, diamond_color=INK,
            title="Bera: symbol b◆ preto (uso sobre fundos claros)"),
        "bera-symbol-color-light.svg": g.symbol(text_color=INK, diamond_color=TERRA_DEEP,
            title="Bera: symbol b◆ color (b preto + diamante terracota)"),
        "bera-symbol-color-dark.svg": g.symbol(text_color=PAPER, diamond_color=GOLD,
            title="Bera: symbol b◆ color (b branco + diamante dourado)"),
        "bera-diamond.svg": diamond_only(title="Bera: diamante (currentColor)"),
        "bera-favicon.svg": g.favicon(title="Bera: symbol b◆ (diamante; cor de referência por tema)"),
    }


if __name__ == "__main__":
    ap = argparse.ArgumentParser(description=__doc__.split("\n")[1])
    ap.add_argument("--font", help="caminho da Versos-Bold.ttf (ou VERSOS_TTF)")
    ap.add_argument("--out", default=str(OUT_DIR_DEFAULT), help="pasta de saída (padrão assets/logo)")
    args = ap.parse_args()
    font = find_font(args.font)
    g = Geometry(font)
    out = Path(args.out)
    out.mkdir(parents=True, exist_ok=True)
    print(f"fonte: {font}\nupm {g.upm} · cap {g.cap} · diamante {g.size:.2f} (half {g.half:.2f}) · "
          f"texto termina em {g.text_end:.2f} · centro do diamante ({g.lockup_cx:.2f}, {g.lockup_cy:.2f})")
    files = build_files(g)
    for name, svg in files.items():
        (out / name).write_text(svg, encoding="utf-8")
        print(f"  escrito {name}  ({len(svg)} bytes)")
    print(f"\n✓ {len(files)} arquivos em {out}/")
