"""Card config shapes shared between the admin write path and the guest read path.

`PreviewImage` lives here rather than beside the renderer configs in `routers/admin_cards`
because the link-preview service needs the same shape to read it back, and a service must
not import a router to get at a model.
"""

from pydantic import BaseModel, ValidationError


class PreviewImage(BaseModel):
    """The picture a link to this event unfurls with (design D2, spec link-preview).

    Stored in a design's `config` rather than in its `assets` on purpose. `assets` is keyed
    by uploaded filename and is the rewrite table `card_html.sanitise` consults, so anything
    in it is by construction something the card document may point at. A preview image is
    not — it is never referenced by the card, and putting it there would let a companion
    file named `og.png` claim the role by accident.
    """

    url: str
    #: Declared in the page's meta tags so a chat application can lay the card out before
    #: the image itself arrives.
    width: int
    height: int
    byte_size: int
    content_type: str


def preview_image_of(config: dict[str, object] | None) -> PreviewImage | None:
    """Read the preview image out of a stored config without validating the whole thing.

    Tolerant on purpose. A draft whose config no longer matches its renderer must still be
    listable so an admin can see it and delete it, and that is exactly the case where full
    validation refuses. A missing or malformed preview reads as absent rather than as an
    error, because a card with no picture is a supported state and a broken page is not.
    """
    raw = (config or {}).get("preview_image")
    if not isinstance(raw, dict):
        return None
    try:
        return PreviewImage.model_validate(raw)
    except ValidationError:
        return None
