"""WorldBuilder:加载并校验一组 manifest(地点/物体/角色),供雾鸦岛运行时(server.live2 → runtime.engine)装载世界。

准备好 manifest 目录 → from_directory() 解析 → validate_refs() 准入校验。素材线用同一批 manifest 的 art 段生成精灵图。
(旧的 build()→AgentMind 入世路径已随重复 agent 实现一并移除;当前世界由 runtime.engine.WorldEngine 直接从 manifest 构建。)
"""

from __future__ import annotations

from pathlib import Path

import yaml

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


class WorldBuilder:
    def __init__(self) -> None:
        self.characters: dict[str, CharacterManifest] = {}
        self.objects: dict[str, ObjectManifest] = {}
        self.places: dict[str, PlaceManifest] = {}

    def add(self, manifest) -> None:
        bucket = {
            "character": self.characters,
            "object": self.objects,
            "place": self.places,
        }[manifest.kind]
        if manifest.id in bucket:
            raise ManifestError(f"重复的 {manifest.kind} id:{manifest.id}")
        bucket[manifest.id] = manifest

    @classmethod
    def from_directory(cls, path: str | Path) -> "WorldBuilder":
        """递归加载目录下所有 *.yaml/*.yml manifest。"""
        builder = cls()
        root = Path(path)
        files = sorted(p for p in root.rglob("*.y*ml") if p.is_file())
        for f in files:
            data = yaml.safe_load(f.read_text(encoding="utf-8"))
            builder.add(load_manifest(data))
        return builder

    def validate_refs(self) -> None:
        """准入:跨实体引用必须成立(物体/邻接/出生地都得存在,姓名唯一)。"""
        names = [c.name for c in self.characters.values()]
        dupes = {n for n in names if names.count(n) > 1}
        if dupes:
            raise ManifestError(f"角色姓名重复(用作 agent 标识,须唯一):{dupes}")
        for pm in self.places.values():
            for oid in pm.objects:
                if oid not in self.objects:
                    raise ManifestError(f"地点 {pm.id} 引用了不存在的物体 {oid}")
            for adj in pm.adjacent:
                if adj not in self.places:
                    raise ManifestError(f"地点 {pm.id} 邻接了不存在的地点 {adj}")
        for cm in self.characters.values():
            if cm.start_location not in self.places:
                raise ManifestError(f"角色 {cm.id} 的出生地 {cm.start_location} 不存在")
