"""Generate the digest Adaptive Card image assets into assets/digest/.

The card is Outlook Actionable Messages (AC v1.0 + Outlook extensions), which cannot
tint text or fill containers with brand color, so every branded surface ships as a PNG.

BUTTONS are rasterized from the EXACT CSS in digest-card-final-mockup.html (the .fbtn /
.bClay / .bMist / .bBone rules copied verbatim below, plus the ghost Dismiss pill),
rendered by headless Edge with real Inter (tools/Inter.ttf, OFL, bundled as a data URI)
and cropped to each element box. The output IS the mockup CSS, pixel-for-pixel, at 1x and
2x (no PIL re-implementation, no line-height guessing). MASTHEADS/STRIPS/LEAD-BAR are the
same svglib/PIL build as before.

Run `python tools/gen_digest_assets.py` from the repo root. Prints the 1x button/link
dims -> paste into email_template._BTN_DIMS.
"""
import base64
import os
import re
import subprocess
import tempfile

from PIL import Image
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM

HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(HERE)
OUT = os.path.join(ROOT, "assets", "digest")
WORDMARK = os.path.join(HERE, "wsa-wordmark.svg")
INTER = os.path.join(HERE, "Inter.ttf")

_EDGE_CANDIDATES = [
    r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
    r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
    r"C:\Program Files\Google\Chrome\Application\chrome.exe",
]
EDGE = next((p for p in _EDGE_CANDIDATES if os.path.exists(p)), None)
DPR = 2   # render at 2x; also emit the 1x downscale

# weekday (Mon=0..Sun=6) -> (band bg, logo fill). Mirrors masthead-week.html exactly.
WEEKDAYS = [
    ("mon", "#2c4a5a", "#dde8ee"), ("tue", "#173f3b", "#f4f1ea"),
    ("wed", "#8a6f38", "#f7f2e4"), ("thu", "#8a4b38", "#f7f1e8"),
    ("fri", "#b04a2e", "#f7f1e8"), ("sat", "#f0ece0", "#2b2620"),
    ("sun", "#2b2620", "#f0ece0"),
]

# Buttons: (asset stem, label, css class). The ghost Dismiss uses .pill.
FBTN = [
    ("btn-clay-reply", "Draft a reply", "bClay"),
    ("btn-clay-proposal", "Draft the proposal", "bClay"),
    ("btn-mist-nudge", "Draft a nudge", "bMist"),
    ("btn-mist-chase", "Draft a chase", "bMist"),
    ("btn-mist-proposal", "Draft the proposal", "bMist"),
    ("btn-bone-open", "Open email", "bBone"),
]
DISMISS = ("btn-dismiss", "Dismiss", "pill")
LINKS = [("link-reply", "Draft a reply"), ("link-nudge", "Draft a nudge"),
         ("link-chase", "Draft a chase"), ("link-proposal", "Draft the proposal")]

# --- CSS copied VERBATIM from digest-card-final-mockup.html (.fbtn/.bClay/.bMist/.bBone),
#     plus the fixed-tone ghost Dismiss pill (one border+text tone that reads on light AND
#     dark card themes) and the .bLink compact-row link. -----------------------------------
_BTN_CSS = """
.fbtn{display:inline-block;cursor:pointer;font-family:'Inter','Segoe UI',sans-serif;font-size:13px;font-weight:600;letter-spacing:.01em;padding:8px 18px;border-radius:8px;}
.bClay{background:#b04a2e;color:#f7f1e8;box-shadow:inset 0 1px 0 rgba(247,241,232,.15),0 1px 2px rgba(0,0,0,.25);}
.bMist{background:#dde8ee;color:#2c4a5a;box-shadow:inset 0 0 0 1px rgba(44,74,90,.12),0 1px 2px rgba(0,0,0,.18);}
.bBone{background:#f0ece0;color:#6b6353;box-shadow:inset 0 0 0 1px rgba(107,99,83,.28),0 1px 2px rgba(0,0,0,.15);padding:8px 16px;}
.pill{display:inline-flex;align-items:center;font-family:'Inter','Segoe UI',sans-serif;padding:7px 15px;border-radius:15px;background:transparent;border:1px solid #8a8578;font-size:12.5px;font-weight:600;color:#a19f9d;}
.bLink{display:inline-flex;align-items:center;gap:5px;font-family:'Inter','Segoe UI',sans-serif;background:transparent;color:#b04a2e;font-size:12.5px;font-weight:600;}
"""


def _hexint(h):
    return int(h.lstrip("#"), 16)


def _inter_face():
    b64 = base64.b64encode(open(INTER, "rb").read()).decode()
    return ("@font-face{font-family:'Inter';src:url(data:font/ttf;base64," + b64
            + ");font-weight:100 900;}")


def _edge_shot(html: str, out_png: str, w=760, h=1400):
    if not EDGE:
        raise RuntimeError("no headless Edge/Chrome found; cannot rasterize the button CSS")
    with tempfile.TemporaryDirectory() as td:
        page = os.path.join(td, "p.html")
        open(page, "w", encoding="utf-8").write(html)
        subprocess.run([
            EDGE, "--headless=new", "--disable-gpu", "--no-sandbox",
            "--user-data-dir=" + os.path.join(td, "prof"),
            "--force-device-scale-factor=%d" % DPR,
            "--window-size=%d,%d" % (w, h),
            "--default-background-color=00000000",
            "--hide-scrollbars", "--screenshot=" + out_png,
            "file:///" + page.replace("\\", "/"),
        ], check=True, capture_output=True)


def _bands(alpha) -> list:
    """Vertical [top,bottom) bands of non-transparent rows (one per stacked element)."""
    W, H = alpha.size
    rows = [alpha.crop((0, y, W, y + 1)).getbbox() is not None for y in range(H)]
    out, y = [], 0
    while y < H:
        if rows[y]:
            y0 = y
            while y < H and rows[y]:
                y += 1
            out.append((y0, y))
        else:
            y += 1
    return out


def render_buttons():
    """Rasterize every button/link from the verbatim CSS in ONE headless pass, split into
    per-element bands, crop each to its box, normalize the button family to a common height
    (so a top-aligned action row lines up), and emit 1x + 2x. Returns {stem: (w1x,h1x)}."""
    els = ([(s, '<span class="fbtn %s">%s</span>' % (c, t)) for (s, t, c) in FBTN]
           + [(DISMISS[0], '<span class="pill">%s</span>' % DISMISS[1])]
           + [(s, '<span class="bLink">%s <b>&rarr;</b></span>' % t) for (s, t) in LINKS])
    # Each element on its own block line with generous padding so shadows never merge.
    cells = "".join('<div style="padding:22px 26px">%s</div>' % inner for _, inner in els)
    html = ("<!doctype html><html><head><meta charset=utf-8><style>" + _inter_face()
            + "html,body{margin:0;background:transparent}" + _BTN_CSS
            + "</style></head><body>" + cells + "</body></html>")
    shot = os.path.join(tempfile.gettempdir(), "_btns_2x.png")
    _edge_shot(html, shot)
    img = Image.open(shot).convert("RGBA")
    bands = _bands(img.getchannel("A"))
    if len(bands) != len(els):
        raise RuntimeError("expected %d button bands, found %d" % (len(els), len(bands)))

    crops = {}
    for (stem, _), (y0, y1) in zip(els, bands):
        band = img.crop((0, y0, img.width, y1))
        crops[stem] = band.crop(band.getchannel("A").getbbox())
    # Normalize the button FAMILY (fbtn + dismiss) to one height so a top-aligned row lines
    # up; the pill is shorter, so it gets centered transparent padding. Links stay natural.
    fam = [s for s, _, _ in FBTN] + [DISMISS[0]]
    common_h = max(crops[s].height for s in fam)
    for s in fam:
        c = crops[s]
        if c.height < common_h:
            canvas = Image.new("RGBA", (c.width, common_h), (0, 0, 0, 0))
            canvas.paste(c, (0, (common_h - c.height) // 2), c)
            crops[s] = canvas

    dims = {}
    for stem, c in crops.items():
        c.save(os.path.join(OUT, stem + "@2x.png"))
        one = c.resize((max(1, round(c.width / DPR)), max(1, round(c.height / DPR))), Image.LANCZOS)
        one.save(os.path.join(OUT, stem + ".png"))
        dims[stem] = one.size
    return dims


# --- masthead / strips / lead-bar (svglib + PIL, unchanged) -------------------
def _recolored_logo_on(band_hex, logo_hex, target_h_2x):
    svg = open(WORDMARK, encoding="utf-8").read()
    svg = re.sub(r"<(path|polygon)\b", r'<\1 fill="%s"' % logo_hex, svg)
    tmp = os.path.join(HERE, "_wm_tmp.svg")
    open(tmp, "w", encoding="utf-8").write(svg)
    try:
        d = svg2rlg(tmp)
        k = target_h_2x / d.height
        d.scale(k, k)
        d.width, d.height = d.width * k, d.height * k
        img = renderPM.drawToPIL(d, bg=_hexint(band_hex))
    finally:
        os.remove(tmp)
    return img.convert("RGB")


def masthead(day, band_hex, logo_hex):
    W, H = 600 * DPR, 54 * DPR
    canvas = Image.new("RGB", (W, H), band_hex)
    logo = _recolored_logo_on(band_hex, logo_hex, 16 * DPR)
    canvas.paste(logo, (20 * DPR, (H - logo.height) // 2))
    canvas.save(os.path.join(OUT, "masthead-%s.png" % day))


def strip(name, hex_, h):
    Image.new("RGB", (600 * DPR, h * DPR), hex_).save(os.path.join(OUT, name))


def leadbar(name, hex_, w, h):
    Image.new("RGB", (w * DPR, h * DPR), hex_).save(os.path.join(OUT, name))


def main():
    os.makedirs(OUT, exist_ok=True)
    for day, band, logo in WEEKDAYS:
        masthead(day, band, logo)
    strip("strip-clay.png", "#8a4b38", 4)
    strip("strip-ochre.png", "#8a6f38", 4)
    leadbar("leadbar-clay.png", "#b04a2e", 3, 48)
    dims = render_buttons()

    print("wrote", len(os.listdir(OUT)), "assets to", OUT)
    print("_BTN_DIMS (1x, paste into email_template.py):")
    for k in sorted(dims):
        print('    "%s": (%d, %d),' % (k, dims[k][0], dims[k][1]))


if __name__ == "__main__":
    main()
