"""Typed ID wrappers per ``contracts.md`` §2.1.

Every ID is a frozen dataclass wrapping an opaque string. The wrapper
gives mypy something to type-check against — a function declared
``def get_domain(d: DomainId)`` cannot accept a ``VmId`` by accident,
even though both wrap strings.

Issuer / lifetime convention (see ``contracts.md`` §2.1):

* ``VmId`` — issued by the SDK/CP on create; persists until VM is undefined.
* ``HostId`` — issued by the CP on host-register; persists.
* ``DomainId`` — issued by the ``HypervisorBackend`` on define;
  engine-specific (libvirt UUID; Firecracker socket name).
* ``VolumeId`` / ``SnapshotId`` — issued by the ``StorageBackend``.
* ``DeviceId`` / ``LeaseId`` — issued by the ``mgf-hrb`` broker.
* ``OperationId`` — issued by the CP on mutating RPC.
* ``TenantId`` — issued by the CP on tenant create.

**Rule:** an ID issued by one engine is never re-interpreted by
another. The libvirt adapter's ``DomainId`` is meaningless to
Firecracker. Translation across engines happens via ``VmId`` ⇄ engine
``DomainId`` mappings, owned by the agent.
"""

from __future__ import annotations

from dataclasses import dataclass


@dataclass(frozen=True, slots=True)
class _OpaqueId:
    """Common parent — keeps wrapper boilerplate in one place.

    Subclasses are zero-cost wrappers that exist purely for typing.
    Each subclass's ``value`` carries the issuer's canonical form.
    """

    value: str

    def __str__(self) -> str:
        return self.value


@dataclass(frozen=True, slots=True)
class VmId(_OpaqueId):
    """Cross-engine VM identifier (D-A1, D-G8 — load-bearing for the registry)."""


@dataclass(frozen=True, slots=True)
class HostId(_OpaqueId):
    """Stable host identifier in the fleet (Phase 1+)."""


@dataclass(frozen=True, slots=True)
class DomainId(_OpaqueId):
    """Engine-specific domain identifier (libvirt UUID, Firecracker socket name, …)."""


@dataclass(frozen=True, slots=True)
class VolumeId(_OpaqueId):
    """Storage-engine volume identifier."""


@dataclass(frozen=True, slots=True)
class SnapshotId(_OpaqueId):
    """Storage-engine snapshot identifier."""


@dataclass(frozen=True, slots=True)
class DeviceId(_OpaqueId):
    """Device URN issued by the ``mgf-hrb`` broker."""


@dataclass(frozen=True, slots=True)
class LeaseId(_OpaqueId):
    """Device-lease URN issued by the ``mgf-hrb`` broker."""


@dataclass(frozen=True, slots=True)
class OperationId(_OpaqueId):
    """Server-issued ID for an async mutating RPC (D-G5)."""


@dataclass(frozen=True, slots=True)
class TenantId(_OpaqueId):
    """Tenant identifier (D-D4; carried in every RPC from day 1)."""


__all__ = [
    "DeviceId",
    "DomainId",
    "HostId",
    "LeaseId",
    "OperationId",
    "SnapshotId",
    "TenantId",
    "VmId",
    "VolumeId",
]
