from __future__ import annotations

from pathlib import Path
from typing import Any

from .builder import create_skill as build_skill
from .builder import update_skill as patch_skill
from .runtime import SkillRegistry


class SkillView(dict):
    def __getattr__(self, item):
        try:
            return self[item]
        except KeyError as exc:
            raise AttributeError(item) from exc



def _resolve_skills_root(config: dict[str, Any]) -> Path:
    if config.get("skills_root"):
        return Path(config["skills_root"]).expanduser().resolve()

    workspace = config.get("workspace", {}) or {}
    if workspace.get("skills_root"):
        return Path(workspace["skills_root"]).expanduser().resolve()
    if workspace.get("skills_dir"):
        return Path(workspace["skills_dir"]).expanduser().resolve()
    if workspace.get("root"):
        return (Path(workspace["root"]).expanduser().resolve() / "skills").resolve()

    return Path("workspace/skills").expanduser().resolve()


class SkillManager:
    def __init__(self, config: dict[str, Any]):
        self.config = dict(config)
        self.root = _resolve_skills_root(self.config)
        self.registry = SkillRegistry(self.root)

    def _serialize_skill(self, name: str) -> dict[str, Any]:
        skill = self.registry.get(name)
        if skill is None:
            return SkillView({"name": name, "error": self.registry.errors.get(name)})
        return SkillView(
            {
                "name": skill.manifest.name,
                "description": skill.manifest.description,
                "version": skill.manifest.version,
                "enabled": skill.manifest.enabled,
                "fingerprint": skill.fingerprint,
                "path": str(skill.path),
                "tools": skill.export.tools,
                "prompts": skill.export.prompts,
                "metadata": skill.export.metadata,
                "bundle_files": skill.manifest.metadata.get("bundle_files", []),
                "error": self.registry.errors.get(name),
            }
        )

    def load_all(self, *, context: dict[str, Any] | None = None) -> list[dict[str, Any]]:
        self.registry = SkillRegistry(self.root)
        self.registry.reload(context=context)
        return [self._serialize_skill(name) for name in sorted(self.registry.skills)]

    def reload_if_needed(self, *, context: dict[str, Any] | None = None):
        return self.registry.reload(context=context)

    def list_skills(self) -> list[dict[str, Any]]:
        names = sorted(set(self.registry.skills) | set(self.registry.errors))
        return [self._serialize_skill(name) for name in names]

    def get_system_prompt_fragments(self) -> list[str]:
        return self.registry.collect_prompt_fragments()

    def get_tools(self) -> list[dict[str, Any]]:
        return self.registry.collect_tools()

    def create_skill(
        self,
        *,
        name: str,
        description: str,
        instructions: str | None = None,
        entrypoint_code: str | None = None,
        with_entrypoint: bool = True,
        extra_files: dict[str, str] | None = None,
        context: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        skill_dir = build_skill(
            self.root,
            name=name,
            description=description,
            instructions=instructions,
            entrypoint_code=entrypoint_code,
            with_entrypoint=with_entrypoint,
            extra_files=extra_files,
        )
        summary = self.reload_if_needed(context=context)
        return {
            "skill_dir": str(skill_dir),
            "extra_files": sorted((extra_files or {}).keys()),
            "reload": {
                "loaded": summary.loaded,
                "reloaded": summary.reloaded,
                "removed": summary.removed,
                "failed": summary.failed,
            },
        }

    def update_skill(
        self,
        *,
        name: str,
        description: str | None = None,
        instructions: str | None = None,
        entrypoint_code: str | None = None,
        manifest_updates: dict[str, Any] | None = None,
        extra_files: dict[str, str] | None = None,
        context: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        result = patch_skill(
            self.root / name,
            description=description,
            instructions=instructions,
            entrypoint_code=entrypoint_code,
            manifest_updates=manifest_updates,
            extra_files=extra_files,
        )
        summary = self.reload_if_needed(context=context)
        return {
            "skill_dir": str(result["skill_dir"]),
            "backup_dir": str(result["backup_dir"]) if result["backup_dir"] else None,
            "extra_files": sorted((extra_files or {}).keys()),
            "reload": {
                "loaded": summary.loaded,
                "reloaded": summary.reloaded,
                "removed": summary.removed,
                "failed": summary.failed,
            },
        }
