#!/usr/bin/env python3
"""Deterministic two-tone wordmark renderer (Pillow).

Use instead of image_generate when the spec demands exact pixel dimensions,
transparent PNG, and exact hex colors (site-builder logo exports,
header/footer pairs, recolors of an established wordmark).

Renders at 4x supersample and LANCZOS-downscales for crisp edges. Glyphs are
scaled to fill `fill` of the canvas; remaining space is transparent padding —
which is also the lever for matching a builder's assumed aspect ratio (see
--width note).

Usage:
    python render_wordmark.py --word1 Pipeline --word2 Layer \
        --color1 "#0B1120" --color2 "#E8893A" \
        --width 700 --height 140 --out pl_header.png \
        --font /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf

Hard-won lessons baked in (Pipeline Layer header/footer job, 2026-08-03):

- COLOR-BOUNDARY COLLISION: word2 must be placed at word1's ADVANCE width
  (textlength), NOT its ink bbox (textbbox). DejaVu Bold's terminal "e" ink
  overhangs into the next glyph's space — bbox placement made the amber "L"
  visibly clip the gray "e". A small explicit --gap at the boundary keeps the
  color break clean. Vision-verify the junction specifically; overall
  spelling can pass while the boundary is clipped.
- ASPECT RATIO vs "ZERO PADDING": a site builder spec said both "zero
  padding, edge-to-edge" AND "e.g. ~5:1" — contradictory for "PipelineLayer"
  (natural ratio ~7.8:1). Shipped at 7.84:1 first; object-contain scaled the
  whole file to display height, so the logo displayed ~55% too wide and Rob
  reported "way bigger." Fix: pass --width to pad the transparent canvas to
  the builder's assumed ratio (e.g. 700x140 = 5:1). When spec clauses
  conflict, the builder's example ratio wins — it drives on-screen size.
- Verify output with vision_analyze composited over the REAL target
  backgrounds (white navbar band, navy footer band) — contrast failures only
  show in context. Cyan #18C8E6 fails on white (~1.4:1); blue #1E5BFF and
  amber #E8893A pass on both.
- VPS ships DejaVu only; download the brand font TTF (e.g. Manrope from
  Google Fonts) first if an exact type match matters.
"""
import argparse

from PIL import Image, ImageDraw, ImageFont


def render(word1, word2, color1, color2, canvas_w, canvas_h, out_path,
           font_path, fill=0.92, gap_frac=0.04, supersample=4):
    ss = supersample
    cw, ch = canvas_w * ss, canvas_h * ss

    d = ImageDraw.Draw(Image.new("L", (10, 10)))

    # Estimate size, measure, rescale so glyphs fill `fill` of both dims.
    size = int(ch * fill / 0.93)
    font = ImageFont.truetype(font_path, size)
    full = word1 + word2
    bbox = d.textbbox((0, 0), full, font=font)
    gw, gh = bbox[2] - bbox[0], bbox[3] - bbox[1]
    scale = min(ch * fill / gh, cw * fill / gw)
    font = ImageFont.truetype(font_path, int(size * scale))

    bbox = d.textbbox((0, 0), full, font=font)
    gw, gh = bbox[2] - bbox[0], bbox[3] - bbox[1]
    w1_adv = d.textlength(word1, font=font)  # advance, NOT ink bbox
    w2_bbox = d.textbbox((0, 0), word2, font=font)
    gap = int(font.size * gap_frac)
    total_w = gw + gap

    img = Image.new("RGBA", (cw, ch), (0, 0, 0, 0))
    dr = ImageDraw.Draw(img)
    ox = (cw - total_w) // 2 - bbox[0]
    oy = (ch - gh) // 2 - bbox[1]
    dr.text((ox, oy), word1, font=font, fill=color1)
    dr.text((ox + int(w1_adv) + gap - w2_bbox[0], oy), word2,
            font=font, fill=color2)

    img = img.resize((canvas_w, canvas_h), Image.LANCZOS)
    img.save(out_path)
    print(f"{out_path}: {img.size[0]}x{img.size[1]}  "
          f"ratio={canvas_w / canvas_h:.2f}")


if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--word1", required=True)
    p.add_argument("--word2", required=True)
    p.add_argument("--color1", required=True, help="word1 hex, e.g. #0B1120")
    p.add_argument("--color2", required=True, help="word2 hex, e.g. #E8893A")
    p.add_argument("--width", type=int, required=True,
                   help="canvas width px; pad to builder's assumed ratio")
    p.add_argument("--height", type=int, required=True,
                   help="canvas height px (export px, e.g. 140 for 70px @2x)")
    p.add_argument("--out", required=True)
    p.add_argument("--font",
                   default="/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf")
    p.add_argument("--fill", type=float, default=0.92)
    p.add_argument("--gap", type=float, default=0.04,
                   help="color-boundary gap as fraction of font size")
    args = p.parse_args()
    render(args.word1, args.word2, args.color1, args.color2,
           args.width, args.height, args.out, args.font,
           args.fill, args.gap)
