"""Manifest 加载:dict / YAML 文件 → 对应 Manifest 对象,按 kind 分发并即时校验。"""

from __future__ import annotations

from pathlib import Path
from typing import Any

import yaml

from genesis.manifest.schema import (
    ArtSpec,
    CharacterManifest,
    ManifestError,
    ObjectManifest,
    PlaceManifest,
)

_KINDS = {
    "character": CharacterManifest,
    "object": ObjectManifest,
    "place": PlaceManifest,
}


def load_manifest(data: dict[str, Any]):
    """从 dict 构造并校验一个 manifest;kind 缺失/未知或字段不合法均抛 ManifestError。"""
    if not isinstance(data, dict):
        raise ManifestError(f"manifest 必须是字典,得到 {type(data)!r}")
    kind = data.get("kind")
    cls = _KINDS.get(kind)
    if cls is None:
        raise ManifestError(f"未知或缺失 kind:{kind!r}(允许 {set(_KINDS)})")

    payload = {k: v for k, v in data.items() if k != "kind"}
    payload["art"] = ArtSpec.from_dict(payload.get("art"))
    known = {f for f in cls.__dataclass_fields__}
    unknown = set(payload) - known
    if unknown:
        raise ManifestError(f"[{data.get('id')}] 含未知字段 {unknown}")
    try:
        manifest = cls(**{k: v for k, v in payload.items() if k in known})
    except TypeError as e:  # 缺必填字段
        raise ManifestError(f"[{data.get('id')}] 字段不全:{e}") from e
    manifest.validate()
    return manifest


def load_manifest_file(path: str | Path):
    """从 YAML 文件加载单个 manifest。"""
    text = Path(path).read_text(encoding="utf-8")
    return load_manifest(yaml.safe_load(text))
