"""
Skill Loader System

Loads and manages skills from SKILL.md files for on-demand knowledge injection.

Inspired by Claude Code's skill system:
- Skills are FOLDERS containing a SKILL.md with YAML frontmatter + markdown body
- Layer 1: Metadata (always loaded, ~100 tokens/skill)  
- Layer 2: SKILL.md body (on trigger, ~2000 tokens)
- Layer 3: Resources (as needed - scripts, references, assets)

Key insight: Skill content goes into tool_result (user message),
NOT system prompt. This preserves prompt cache!
"""

import re
from pathlib import Path
from typing import Optional


class SkillLoader:
    """
    Loads and manages skills from SKILL.md files.
    
    A skill is a FOLDER containing:
    - SKILL.md (required): YAML frontmatter + markdown instructions
    - scripts/ (optional): Helper scripts
    - references/ (optional): Additional docs
    - assets/ (optional): Templates, files
    
    SKILL.md Format:
        ---
        name: python-testing
        description: Python testing best practices with pytest
        ---
        # Python Testing Skill
        ## How to write tests...
    """
    
    def __init__(self, skills_dir: Path):
        self.skills_dir = skills_dir
        self.skills: dict[str, dict] = {}
        self.load_skills()
    
    def parse_skill_md(self, path: Path) -> Optional[dict]:
        """Parse a SKILL.md file into metadata and body."""
        try:
            content = path.read_text(encoding="utf-8")
        except Exception:
            return None
        
        # Match YAML frontmatter between --- markers
        match = re.match(r"^---\s*\n(.*?)\n---\s*\n(.*)$", content, re.DOTALL)
        if not match:
            return None
        
        frontmatter, body = match.groups()
        
        # Parse YAML-like frontmatter (simple key: value)
        metadata = {}
        for line in frontmatter.strip().split("\n"):
            if ":" in line:
                key, value = line.split(":", 1)
                metadata[key.strip()] = value.strip().strip("\"'")
        
        # Require name and description
        if "name" not in metadata or "description" not in metadata:
            return None
        
        return {
            "name": metadata["name"],
            "description": metadata["description"],
            "version": metadata.get("version", "1.0"),
            "body": body.strip(),
            "path": path,
            "dir": path.parent,
        }
    
    def load_skills(self) -> None:
        """
        Scan skills directory and load all valid SKILL.md files.
        Only loads metadata at startup - body is loaded on-demand.
        """
        if not self.skills_dir.exists():
            self.skills_dir.mkdir(parents=True, exist_ok=True)
            return
        
        for skill_dir in self.skills_dir.iterdir():
            if not skill_dir.is_dir():
                continue
            
            skill_md = skill_dir / "SKILL.md"
            if not skill_md.exists():
                continue
            
            skill = self.parse_skill_md(skill_md)
            if skill:
                self.skills[skill["name"]] = skill
    
    def get_descriptions(self) -> str:
        """
        Generate skill descriptions for system prompt (Layer 1).
        Only name and description, ~100 tokens per skill.
        """
        if not self.skills:
            return "(no skills available)"
        
        return "\n".join(
            f"- {name}: {skill['description']}"
            for name, skill in sorted(self.skills.items())
        )
    
    def get_skill_content(self, name: str) -> Optional[str]:
        """
        Get full skill content for injection (Layer 2 + Layer 3 hints).
        Returns None if skill not found.
        """
        if name not in self.skills:
            return None
        
        skill = self.skills[name]
        content = f"# Skill: {skill['name']}\n\n{skill['body']}"
        
        # List available resources (Layer 3 hints)
        resources = []
        for folder, label in [
            ("scripts", "Scripts"),
            ("references", "References"),
            ("assets", "Assets"),
        ]:
            folder_path = skill["dir"] / folder
            if folder_path.exists():
                files = list(folder_path.glob("*"))
                if files:
                    resources.append(f"{label}: {', '.join(f.name for f in files)}")
        
        if resources:
            content += f"\n\n**Available resources in {skill['dir']}:**\n"
            content += "\n".join(f"- {r}" for r in resources)
        
        return content
    
    def list_skills(self) -> list[str]:
        """Return list of available skill names."""
        return sorted(self.skills.keys())
    
    def reload(self) -> None:
        """Reload all skills from disk."""
        self.skills.clear()
        self.load_skills()
