"""Binary content validation via magic-number detection.

Catches corrupted or truncated font and image files before they are
embedded into OOXML/ODF packages.

See ADR 020, item 5.
"""

from __future__ import annotations

# ---------------------------------------------------------------------------
# Magic bytes
# ---------------------------------------------------------------------------

TTF_MAGIC = b"\x00\x01\x00\x00"
OTF_MAGIC = b"OTTO"
TTC_MAGIC = b"ttcf"
WOFF_MAGIC = b"wOFF"
WOFF2_MAGIC = b"wOF2"

JPEG_MAGIC = b"\xff\xd8\xff"
PNG_MAGIC = b"\x89PNG\r\n\x1a\n"
GIF87_MAGIC = b"GIF87a"
GIF89_MAGIC = b"GIF89a"
BMP_MAGIC = b"BM"
TIFF_LE_MAGIC = b"II\x2a\x00"
TIFF_BE_MAGIC = b"MM\x00\x2a"
EMF_MAGIC = b"\x01\x00\x00\x00"  # + size at offset 40

_FONT_MAGICS = (TTF_MAGIC, OTF_MAGIC, TTC_MAGIC, WOFF_MAGIC, WOFF2_MAGIC)
_IMAGE_MAGICS = (
    (JPEG_MAGIC, "jpeg"),
    (PNG_MAGIC, "png"),
    (GIF87_MAGIC, "gif"),
    (GIF89_MAGIC, "gif"),
    (BMP_MAGIC, "bmp"),
    (TIFF_LE_MAGIC, "tiff"),
    (TIFF_BE_MAGIC, "tiff"),
)

# Minimum plausible sizes (header only)
_MIN_FONT_SIZE = 12
_MIN_IMAGE_SIZE = 8


def validate_font(data: bytes) -> bool:
    """Return ``True`` if *data* starts with a recognised font header.

    Accepts TTF, OTF, TTC, WOFF, and WOFF2.
    """
    if len(data) < _MIN_FONT_SIZE:
        return False
    return data[:4] in _FONT_MAGICS


def validate_image(data: bytes) -> bool:
    """Return ``True`` if *data* starts with a recognised image header.

    Accepts JPEG, PNG, GIF, BMP, and TIFF.
    """
    if len(data) < _MIN_IMAGE_SIZE:
        return False
    for magic, _ in _IMAGE_MAGICS:
        if data[: len(magic)] == magic:
            return True
    return False


def detect_binary_format(data: bytes) -> str | None:
    """Detect the binary format from magic bytes.

    Returns a short name (``"ttf"``, ``"otf"``, ``"png"``, etc.) or
    ``None`` if the format is not recognised.
    """
    if len(data) < 4:
        return None

    head = data[:4]

    # Fonts
    if head == TTF_MAGIC:
        return "ttf"
    if head == OTF_MAGIC:
        return "otf"
    if head == TTC_MAGIC:
        return "ttc"
    if head == WOFF_MAGIC:
        return "woff"
    if head == WOFF2_MAGIC:
        return "woff2"

    # Images
    for magic, name in _IMAGE_MAGICS:
        if data[: len(magic)] == magic:
            return name

    return None
