"""Framing scale enum SOT for shot_staging.framing_scale.

No regex fallback. Missing or invalid framing_scale fails fast with AppError.
"""

from collections.abc import Mapping
from typing import Optional

from app.core.errors import AppError

FRAMING_CLOSE = "close"
FRAMING_MEDIUM = "medium"
FRAMING_WIDE = "wide"
FRAMING_INSERT = "insert"

VALID_FRAMING_SCALES = frozenset(
    {
        FRAMING_CLOSE,
        FRAMING_MEDIUM,
        FRAMING_WIDE,
        FRAMING_INSERT,
    }
)


def get_framing_scale_or_raise(
    staging: Optional[Mapping[str, object]],
    *,
    where: str,
) -> str:
    """Read the required framing_scale enum from shot_staging output."""
    if not isinstance(staging, Mapping):
        raise AppError(
            code="shot_staging.framing_scale_missing",
            message=(
                f"framing_scale read failed at {where}: staging is not a mapping "
                f"(got {type(staging).__name__})"
            ),
            status_code=422,
        )

    value = staging.get("framing_scale")
    if value is None:
        raise AppError(
            code="shot_staging.framing_scale_missing",
            message=(
                f"framing_scale read failed at {where}: key absent. Legacy "
                "shot_staging cp likely; force re-run shot_staging step."
            ),
            status_code=422,
        )

    if not isinstance(value, str) or value not in VALID_FRAMING_SCALES:
        raise AppError(
            code="shot_staging.framing_scale_invalid",
            message=(
                f"framing_scale invalid at {where}: got {value!r}, "
                f"expected one of {sorted(VALID_FRAMING_SCALES)}"
            ),
            status_code=422,
        )

    return value
