"""Reproduce the 2026-09-25 PNG-to-ICO article measurements with Pillow 12.3.0."""

from __future__ import annotations

import csv
import struct
from pathlib import Path

from PIL import Image, ImageDraw, __version__ as pillow_version


ROOT = Path(__file__).resolve().parents[2]
OUT = ROOT / "assets" / "ico-file-audit"
SIZES = (16, 32, 48, 256)


def make_artwork(size: tuple[int, int], opaque: bool = False) -> Image.Image:
    image = Image.new("RGBA", size, "white" if opaque else (0, 0, 0, 0))
    draw = ImageDraw.Draw(image)
    width, height = size
    margin = min(width, height) // 5
    draw.rounded_rectangle(
        (margin, margin, width - margin - 1, height - margin - 1),
        radius=max(2, margin // 2),
        fill=(20, 95, 140, 255),
    )
    draw.ellipse(
        (width * 2 // 5, height * 2 // 5, width * 3 // 5, height * 3 // 5),
        fill=(255, 190, 60, 255),
    )
    return image


def ico_entries(data: bytes) -> list[tuple[int, int, str]]:
    reserved, kind, count = struct.unpack_from("<HHH", data)
    assert (reserved, kind) == (0, 1)
    entries = []
    for index in range(count):
        offset = 6 + 16 * index
        width, height, _, _, _, _, length, start = struct.unpack_from("<BBBBHHII", data, offset)
        payload = data[start : start + length]
        assert len(payload) == length
        encoding = "PNG" if payload.startswith(b"\x89PNG\r\n\x1a\n") else "BMP"
        entries.append((width or 256, height or 256, encoding))
    return entries


def transparent_pixels(path: Path, size: int) -> str:
    with Image.open(path) as image:
        if (size, size) not in image.ico.sizes():
            return "not present"
        layer = image.ico.getimage((size, size)).convert("RGBA")
        alpha = layer.getchannel("A")
        histogram = alpha.histogram()
        return str(sum(histogram[:255]))


def main() -> None:
    assert pillow_version == "12.3.0", f"Recheck recorded numbers with Pillow {pillow_version}"
    OUT.mkdir(parents=True, exist_ok=True)
    cases = [
        ("square-transparent", make_artwork((320, 320)), "none"),
        ("square-opaque", make_artwork((320, 320), opaque=True), "none"),
        ("tiny-transparent", make_artwork((24, 24)), "none"),
    ]
    wide = make_artwork((480, 240))
    wide.save(OUT / "wide-original.png")
    padded = Image.new("RGBA", (480, 480), (0, 0, 0, 0))
    padded.alpha_composite(wide, (0, 120))
    cases.append(("wide-padded", padded, "480x240 centered on 480x480 transparent canvas"))

    rows = []
    for name, image, preparation in cases:
        source = OUT / f"{name}.png"
        target = OUT / f"{name}.ico"
        image.save(source)
        image.save(target, format="ICO", sizes=[(n, n) for n in SIZES])
        entries = ico_entries(target.read_bytes())
        rows.append({
            "case": name,
            "source_dimensions_px": f"{image.width}x{image.height}",
            "source_bytes": source.stat().st_size,
            "preparation": preparation,
            "ico_bytes": target.stat().st_size,
            "requested_sizes_px": "/".join(map(str, SIZES)),
            "actual_sizes_px": "/".join(str(width) for width, _, _ in entries),
            "entry_encoding": "/".join(encoding for _, _, encoding in entries),
            "nonopaque_pixels_16": transparent_pixels(target, 16),
            "nonopaque_pixels_256": transparent_pixels(target, 256),
        })

    with (OUT / "measurements.csv").open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=rows[0].keys())
        writer.writeheader()
        writer.writerows(rows)
    for row in rows:
        print(row)


if __name__ == "__main__":
    main()
