"""VM naming rules — the engine-neutral identity constraints for a VM.

A pure, stdlib-only leaf (``re`` only). It exists as its own module so
that the naming rule can be shared by the spec validator, the rename
operation, and the clone operation **without** any of them importing
each other (in mgf-vm, ``lifecycle.rename`` and ``operations.clone``
both reached into ``creator.validator`` just for ``VM_NAME_REGEX``,
dragging in the whole creator surface). The rule belongs to the domain,
not to any one operation.

The constraint (documented in the architecture review): a VM name must
start with an alphanumeric, then allow alphanumeric / underscore / dot /
hyphen, 1-63 characters total. That keeps a name safe to embed in
filesystem paths, shell arguments, and libvirt domain names.
"""

from __future__ import annotations

import re

#: Must start alphanumeric, then alphanumeric / ``_`` / ``.`` / ``-``,
#: 1-63 chars total.
VM_NAME_REGEX = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,62}$")

#: Human-readable description of the rule, for error messages.
VM_NAME_RULE = (
    "must start with a letter or digit; then letters, digits, "
    "underscore, dot, or hyphen; 1-63 chars"
)

__all__ = ["VM_NAME_REGEX", "VM_NAME_RULE", "is_valid_vm_name"]


def is_valid_vm_name(name: str) -> bool:
    """Return ``True`` if ``name`` satisfies :data:`VM_NAME_REGEX`.

    Non-string or empty input is invalid (returns ``False``), never
    raises — callers that need a typed error build it from
    :data:`VM_NAME_RULE`.
    """
    return isinstance(name, str) and VM_NAME_REGEX.match(name) is not None
