from __future__ import annotations

import binascii
import struct
import zlib

from packages.pet_package_schema import ALLOWED_ACTIONS, DEFAULT_FRAMES_PER_ACTION


WIDTH = 192
HEIGHT = 208
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
STRIP_FRAMES = DEFAULT_FRAMES_PER_ACTION


def build_action_strip_layout_guide_png(*, action: str) -> bytes:
    if action not in ALLOWED_ACTIONS:
        raise ValueError(f"unsupported action for layout guide: {action}")

    width = WIDTH * STRIP_FRAMES
    canvas = [(247, 247, 247, 255)] * (width * HEIGHT)
    border = (18, 18, 18, 255)
    safe = (47, 128, 237, 255)
    center = (184, 184, 184, 255)

    for frame_index in range(STRIP_FRAMES):
        left = frame_index * WIDTH
        right = left + WIDTH - 1
        _draw_rect(canvas, width, left, 0, right, HEIGHT - 1, border, 2)
        _draw_rect(canvas, width, left + 18, 16, right - 18, HEIGHT - 17, safe, 2)
        _draw_dashed_vertical(canvas, width, left + WIDTH // 2, 16, HEIGHT - 17, center)
        _draw_dashed_horizontal(canvas, width, left + 18, right - 18, HEIGHT // 2, center)

    return _write_rgba_png(width, HEIGHT, canvas)


def _draw_rect(
    canvas: list[tuple[int, int, int, int]],
    width: int,
    x0: int,
    y0: int,
    x1: int,
    y1: int,
    color: tuple[int, int, int, int],
    thickness: int,
) -> None:
    for offset in range(thickness):
        for x in range(x0 + offset, x1 - offset + 1):
            _set_pixel(canvas, width, x, y0 + offset, color)
            _set_pixel(canvas, width, x, y1 - offset, color)
        for y in range(y0 + offset, y1 - offset + 1):
            _set_pixel(canvas, width, x0 + offset, y, color)
            _set_pixel(canvas, width, x1 - offset, y, color)


def _draw_dashed_vertical(
    canvas: list[tuple[int, int, int, int]],
    width: int,
    x: int,
    y0: int,
    y1: int,
    color: tuple[int, int, int, int],
) -> None:
    for y in range(y0, y1 + 1, 14):
        for draw_y in range(y, min(y + 8, y1 + 1)):
            _set_pixel(canvas, width, x, draw_y, color)


def _draw_dashed_horizontal(
    canvas: list[tuple[int, int, int, int]],
    width: int,
    x0: int,
    x1: int,
    y: int,
    color: tuple[int, int, int, int],
) -> None:
    for x in range(x0, x1 + 1, 14):
        for draw_x in range(x, min(x + 8, x1 + 1)):
            _set_pixel(canvas, width, draw_x, y, color)


def _set_pixel(
    canvas: list[tuple[int, int, int, int]],
    width: int,
    x: int,
    y: int,
    color: tuple[int, int, int, int],
) -> None:
    if 0 <= x < width and 0 <= y < HEIGHT:
        canvas[y * width + x] = color


def _write_rgba_png(width: int, height: int, pixels: list[tuple[int, int, int, int]]) -> bytes:
    rows = bytearray()
    for y in range(height):
        rows.append(0)
        for red, green, blue, alpha in pixels[y * width : (y + 1) * width]:
            rows.extend((red, green, blue, alpha))
    chunks = [
        _png_chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0)),
        _png_chunk(b"IDAT", zlib.compress(bytes(rows))),
        _png_chunk(b"IEND", b""),
    ]
    return PNG_SIGNATURE + b"".join(chunks)


def _png_chunk(kind: bytes, data: bytes) -> bytes:
    return struct.pack(">I", len(data)) + kind + data + struct.pack(">I", binascii.crc32(kind + data) & 0xFFFFFFFF)
