from __future__ import annotations

import shutil
from pathlib import Path
from typing import Any

from niannian.skills.registry import SkillRecord, load_state, parse_skill_file, save_state


class SkillLoader:
    """扫描 skills/default + skills/custom，合并 state.json。"""

    def __init__(self, root: Path, *, state_file: Path | None = None) -> None:
        self._root = root
        self._state_path = state_file or root / "state.json"
        self._cache: dict[str, SkillRecord] = {}
        self._mtimes: dict[str, float] = {}

    @property
    def root(self) -> Path:
        return self._root

    def reload(self) -> list[SkillRecord]:
        self._cache.clear()
        state = load_state(self._state_path)
        for sub, readonly in (("default", True), ("custom", False)):
            base = self._root / sub
            if not base.is_dir():
                continue
            for skill_md in base.rglob("SKILL.md"):
                rec = parse_skill_file(skill_md, readonly=readonly)
                if rec is None:
                    continue
                override = state.get(rec.name, {})
                if "enabled" in override:
                    rec.enabled = bool(override["enabled"])
                self._cache[rec.name] = rec
                self._mtimes[rec.name] = skill_md.stat().st_mtime
        return self._sorted_skills()

    def _sorted_skills(self) -> list[SkillRecord]:
        return sorted(self._cache.values(), key=lambda s: (-s.priority, s.name))

    def list_skills(self) -> list[SkillRecord]:
        if not self._cache and self._root.is_dir():
            self.reload()
        return self._sorted_skills()

    def get(self, name: str) -> SkillRecord | None:
        if not self._cache:
            self.reload()
        return self._cache.get(name)

    def set_enabled(self, name: str, enabled: bool) -> SkillRecord:
        if not self._cache:
            self.reload()
        rec = self._cache.get(name)
        if rec is None:
            raise KeyError(name)
        state = load_state(self._state_path)
        state.setdefault(name, {})["enabled"] = enabled
        save_state(self._state_path, state)
        rec.enabled = enabled
        return rec

    def write_custom(self, name: str, content: str) -> SkillRecord:
        custom_dir = self._root / "custom" / name
        custom_dir.mkdir(parents=True, exist_ok=True)
        path = custom_dir / "SKILL.md"
        path.write_text(content, encoding="utf-8")
        rec = parse_skill_file(path, readonly=False)
        if rec is None:
            raise ValueError("invalid SKILL.md content")
        self._cache[rec.name] = rec
        return rec

    def delete_custom(self, name: str) -> None:
        if not self._cache:
            self.reload()
        rec = self._cache.get(name)
        if rec is None:
            raise KeyError(name)
        if rec.readonly:
            raise ValueError("cannot delete readonly skill")
        custom_dir = self._root / "custom" / name
        if not custom_dir.is_dir():
            raise ValueError("not a custom skill")
        shutil.rmtree(custom_dir)
        self._cache.pop(name, None)
        self._mtimes.pop(name, None)
        state = load_state(self._state_path)
        if name in state:
            del state[name]
            save_state(self._state_path, state)
