"""Simple manifest loader for mindmodel manifests.

Provides `load_manifest(path: str) -> dict` and `ManifestLoadError`.

Behavior:
- If PyYAML is installed, uses yaml.safe_load to parse the file.
- Otherwise falls back to the stdlib json parser.
- If the top-level document is a list it will be normalized to {"constraints": <list>}.
- Raises ManifestLoadError for missing file or parse errors.
"""

from typing import Any, Dict
import json
from pathlib import Path


class ManifestLoadError(Exception):
    """Raised when a manifest cannot be loaded or parsed."""


try:
    import yaml  # type: ignore
except Exception:  # YAML not available
    yaml = None  # type: ignore


def _parse_with_yaml(text: str) -> Any:
    # yamlsafe_load may return any Python structure
    try:
        return yaml.safe_load(text)
    except Exception as exc:  # pragma: no cover - defensive
        raise ManifestLoadError(f"YAML parse error: {exc}") from exc


def _parse_with_json(text: str) -> Any:
    try:
        return json.loads(text)
    except Exception as exc:
        raise ManifestLoadError(f"JSON parse error: {exc}") from exc


def load_manifest(path: str) -> Dict[str, Any]:
    """Load a manifest from the given file path and normalize it to a dict.

    If the top-level document is a list, it will be returned as {"constraints": list}.
    Raises ManifestLoadError if the file does not exist or if parsing fails.
    """
    p = Path(path)
    if not p.exists():
        raise ManifestLoadError(f"Manifest file not found: {path}")

    text = p.read_text(encoding="utf-8")

    if yaml is not None:
        data = _parse_with_yaml(text)
    else:
        data = _parse_with_json(text)

    # Normalize
    if isinstance(data, list):
        return {"constraints": data}

    if isinstance(data, dict):
        return data

    # Unexpected top-level type, wrap it
    return {"manifest": data}
