"""C7 inference runtime DTOs + enums (AZ-297) — L1 shared types.

Hosted at the ``_types`` layer (not under ``components/c7_inference``)
because C10 ``CacheProvisioner`` re-exports :class:`EngineCacheEntry`
as part of its own Public API; per the architecture rule
(``test_az270_compose_root.py`` AC-6) components MUST NOT import
other components, so cross-component DTOs live in ``_types/``.

C7's :class:`gps_denied_onboard.components.c7_inference` package
re-exports these names for the canonical contract surface; consumers
SHOULD import from ``c7_inference`` (the contract namespace) rather
than from here. The contract at
``_docs/02_document/contracts/c7_inference/inference_runtime_protocol.md``
v1.0.0 is the authoritative shape; this module mirrors it 1:1.
"""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from pathlib import Path

__all__ = [
    "BuildConfig",
    "EngineCacheEntry",
    "EngineHandle",
    "OptimizationProfile",
    "PrecisionMode",
]


class PrecisionMode(str, Enum):
    """TensorRT / ORT / PyTorch precision the engine is compiled for."""

    FP16 = "fp16"
    INT8 = "int8"
    MIXED = "mixed"


@dataclass(frozen=True)
class OptimizationProfile:
    """One named TRT optimisation profile.

    The runtime picks an actual shape inside ``[min_shape, max_shape]``
    based on the input dict supplied to ``infer``; the Protocol does
    NOT auto-batch (see ``inference_runtime_protocol.md`` Non-Goals).
    """

    input_name: str
    min_shape: tuple[int, ...]
    opt_shape: tuple[int, ...]
    max_shape: tuple[int, ...]


@dataclass(frozen=True)
class BuildConfig:
    """Engine-build hyperparameters passed to ``compile_engine``.

    ``calibration_dataset`` is required when ``precision == INT8`` and
    is ``None`` for FP16 / MIXED. ``use_trtexec`` is a TRT-only hint;
    the ORT / PyTorch strategies ignore it.
    """

    precision: PrecisionMode
    workspace_mb: int
    calibration_dataset: Path | None
    optimization_profiles: tuple[OptimizationProfile, ...]
    use_trtexec: bool = False


@dataclass(frozen=True)
class EngineCacheEntry:
    """Self-describing pointer to a compiled engine on disk.

    The five-tuple ``(model, sm, jp, trt, precision)`` matches the
    filename schema from AZ-281 (``engine_filename_schema.md``);
    ``sha256_hex`` is produced via the AZ-280 sidecar pattern. For
    PyTorch baselines the ``sm`` / ``jp`` / ``trt`` fields are ``None``
    (the runtime is hardware-portable). ``extras`` carries
    strategy-specific metadata (e.g., calibration cache path).
    """

    engine_path: Path
    sha256_hex: str
    sm: int | None
    jp: str | None
    trt: str | None
    precision: PrecisionMode
    extras: dict[str, str]


class EngineHandle:
    """Opaque token returned by C7 ``deserialize_engine``.

    Consumers MUST pass the handle back to the same runtime
    (``infer`` / ``release_engine``) and MUST NOT introspect fields —
    Invariant I-4 of ``inference_runtime_protocol.md``. Each concrete
    strategy subclasses this with implementation-private state.

    A separate :class:`gps_denied_onboard._types.manifests.EngineHandle`
    Protocol exists for the LightGlue consumer-side cut (descriptor_dim
    + forward). That is a duck-typed structural cut, intentionally
    distinct from this opaque marker; concrete C7 strategies subclass
    THIS class and structurally satisfy the LightGlue Protocol when
    paired with a matching engine binary.
    """
