from __future__ import annotations

import struct
import zlib
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1] / "app" / "static" / "images"


def png_chunk(tag: bytes, data: bytes) -> bytes:
    return struct.pack("!I", len(data)) + tag + data + struct.pack("!I", zlib.crc32(tag + data) & 0xFFFFFFFF)


def save_png(path: Path, width: int, height: int, rgba_rows: list[bytes]) -> None:
    raw = b"".join(b"\x00" + row for row in rgba_rows)
    header = struct.pack("!IIBBBBB", width, height, 8, 6, 0, 0, 0)
    content = b"".join(
        [
            b"\x89PNG\r\n\x1a\n",
            png_chunk(b"IHDR", header),
            png_chunk(b"IDAT", zlib.compress(raw, 9)),
            png_chunk(b"IEND", b""),
        ]
    )
    path.write_bytes(content)


def lerp(a: int, b: int, t: float) -> int:
    return int(a + (b - a) * t)


def rounded_square_icon(size: int) -> list[bytes]:
    rows = []
    radius = size * 0.22
    for y in range(size):
        row = bytearray()
        for x in range(size):
            dx = min(x, size - 1 - x)
            dy = min(y, size - 1 - y)
            in_corner = (dx < radius and dy < radius)
            if in_corner:
                cx = radius - dx
                cy = radius - dy
                inside = cx * cx + cy * cy <= radius * radius
            else:
                inside = True

            if not inside:
                row.extend((0, 0, 0, 0))
                continue

            t = (x + y) / (2 * size)
            r = lerp(37, 52, t)
            g = lerp(99, 211, t)
            b = lerp(235, 153, t)

            if (x - size * 0.5) ** 2 + (y - size * 0.48) ** 2 < (size * 0.33) ** 2:
                r, g, b = 250, 252, 255

            roof = abs(x - size * 0.5) + (y - size * 0.40)
            if roof < size * 0.19 and y < size * 0.55:
                r, g, b = 37, 99, 235

            if size * 0.33 < x < size * 0.67 and size * 0.52 < y < size * 0.80:
                r, g, b = 159, 208, 255

            star_x = x - size * 0.68
            star_y = y - size * 0.28
            if abs(star_x) + abs(star_y) < size * 0.06 or (abs(star_x) < size * 0.018 or abs(star_y) < size * 0.018):
                r, g, b = 245, 158, 11

            row.extend((r, g, b, 255))
        rows.append(bytes(row))
    return rows


def badge_icon(size: int) -> list[bytes]:
    rows = []
    radius = size * 0.48
    cx = cy = size / 2
    for y in range(size):
        row = bytearray()
        for x in range(size):
            if (x - cx) ** 2 + (y - cy) ** 2 > radius ** 2:
                row.extend((0, 0, 0, 0))
                continue
            row.extend((37, 99, 235, 255))
        rows.append(bytes(row))
    return rows


def main() -> None:
    ROOT.mkdir(parents=True, exist_ok=True)
    save_png(ROOT / "pwa-icon-192.png", 192, 192, rounded_square_icon(192))
    save_png(Path(__file__).resolve().parents[1] / "icon.png", 256, 256, rounded_square_icon(256))
    save_png(ROOT / "pwa-icon-512.png", 512, 512, rounded_square_icon(512))
    save_png(ROOT / "apple-touch-icon.png", 180, 180, rounded_square_icon(180))
    save_png(ROOT / "pwa-badge.png", 96, 96, badge_icon(96))


if __name__ == "__main__":
    main()
