"""Load a :class:`VMSpec` from a YAML / JSON file and validate it.

The unattended path is the one ``vmanager vm create --config FILE``
uses, plus every automation story (CI, labs, templates) that starts
from a spec file on disk. Everything routes through
:func:`load_and_validate`, which is a thin composition of
:meth:`VMSpec.from_yaml_file` and
:func:`mgf.vm.core.creator.validator.validate` — the two gates a spec
must pass before the (adapter-bound) builder will touch it.

The loader's job is to surface **every** error at once rather than
one-error-per-round: a YAML parse error, a typo'd field, and a too-low
RAM value should all be reported together so users do not have to
fix-and-retry. This works because :class:`SpecValidationError` already
carries a list of errors; the loader simply does not short-circuit on
the first failure.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from mgf.vm.core.creator.spec import VMSpec
from mgf.vm.core.creator.validator import validate
from mgf.vm.core.exceptions import SpecValidationError

if TYPE_CHECKING:
    from pathlib import Path

    from mgf.vm.core.creator.validator import _NameNetworkProvider


def load_and_validate(
    path: Path,
    provider: _NameNetworkProvider | None = None,
    *,
    lenient_source: bool = False,
) -> VMSpec:
    """Parse ``path`` into a :class:`VMSpec` and run it through the validator.

    A missing file, malformed YAML, unknown keys, and every validation
    rule all surface as a single :class:`SpecValidationError`. Callers
    (the CLI layer) catch it once and print ``exc.errors`` — no retry
    loop needed.

    ``provider=None`` skips live-state rules (name uniqueness, network
    existence) so the loader can be used without a backend connection —
    useful for linting spec files in CI.
    """
    spec = VMSpec.from_yaml_file(path)
    validate(spec, provider, lenient_source=lenient_source)
    return spec


def load(path: Path) -> VMSpec:
    """Parse ``path`` into a :class:`VMSpec` without validation.

    Used by template-save and friends — the caller already has a
    validated spec and just wants the on-disk YAML round-tripped through
    the same parser the creation path uses.
    """
    return VMSpec.from_yaml_file(path)


def lint(path: Path) -> list[str]:
    """Return the list of validation errors without raising.

    Used by ``vmanager vm create --config FILE --lint`` and by template
    linting for scripted spec-file checks. Returns an empty list when the
    spec is clean.
    """
    try:
        load_and_validate(path)
    except SpecValidationError as e:
        return list(e.errors)
    return []


__all__ = ["lint", "load", "load_and_validate"]
