# Flag near-white knitr PNG figures (Windows GDI + simsun blank plots)
# and PNGs whose background is mostly transparent.
# theme_tech clears plot.background, so ggsave() without bg="white"
# writes a transparent canvas. Pillow's RGB conversion paints that
# canvas black, which used to look "not white" and pass this gate.
# ASCII-only source.
# Usage: python check-fig-png.py <figure-dir> [<figure-dir> ...]
#   e.g. python scripts/book-plot/py/check-fig-png.py report/ch2_files/figure-html
# Exit: 0 all ok; 1 blank or transparent png, or no png; 2 usage / missing Pillow.
from __future__ import annotations

import sys
from pathlib import Path

try:
    from PIL import Image
except ImportError:  # pragma: no cover
    print("need Pillow: pip install Pillow", file=sys.stderr)
    sys.exit(2)

MEAN_MIN = 250.0
STD_MAX = 8.0
# Anti-aliased ink stays well under this. A cleared plot.background does not.
TRANS_FRAC = 0.05


def is_blank(path: Path) -> tuple[bool, str]:
    with Image.open(path) as im:
        if "A" in im.getbands():
            alpha = im.getchannel("A")
            hist_a = alpha.histogram()
            n_a = sum(hist_a)
            # Not fully opaque. Glyph edges are a few pixels; a clear canvas is not.
            clear = sum(hist_a[:250])
            if n_a and clear / n_a >= TRANS_FRAC:
                return True, f"transparent={clear / n_a:.2f} {alpha.size[0]}x{alpha.size[1]}"
        rgb = im.convert("RGB")
        w, h = rgb.size
        n = w * h
        if n < 1:
            return True, "empty"
        hist = rgb.histogram()
        # mean of R,G,B combined
        s = 0.0
        for ch in range(3):
            base = ch * 256
            s += sum(i * hist[base + i] for i in range(256))
        mean = s / (3.0 * n)
        # rough std from 8-bit bins
        var = 0.0
        for ch in range(3):
            base = ch * 256
            var += sum(((i - mean) ** 2) * hist[base + i] for i in range(256))
        std = (var / (3.0 * n)) ** 0.5
        blank = mean >= MEAN_MIN and std <= STD_MAX
        return blank, f"mean={mean:.1f} std={std:.1f} {w}x{h}"


def main(argv: list[str]) -> int:
    if len(argv) < 2:
        print("usage: python check-fig-png.py <figure-dir> [...]", file=sys.stderr)
        return 2
    dirs = [Path(a) for a in argv[1:]]
    bad: list[str] = []
    n = 0
    for d in dirs:
        if not d.is_dir():
            print(f"skip (not a dir): {d.as_posix()}", file=sys.stderr)
            continue
        for p in sorted(d.glob("*.png")):
            n += 1
            blank, msg = is_blank(p)
            line = f"{p.as_posix()} {msg}"
            if blank:
                bad.append(line)
                tag = "CLEAR" if "transparent=" in msg else "BLANK"
                print(tag, line)
            else:
                print("ok   ", line)
    if n == 0:
        print("no png found", file=sys.stderr)
        return 1
    if bad:
        print(f"blank png: {len(bad)} / {n}", file=sys.stderr)
        return 1
    print(f"png ok: {n} files")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
