# ClawTex — Governed Agent with Genetic Memory
# Built by DeVere Cooley / AN2B LLC · an2b.com
# BB4C — Breath Before Code

"""
Skill loader — discovers and loads ClawTex skills from the skills/ directory.

A skill is a directory containing a SKILL.md file (and optionally Python modules).
The loader reads SKILL.md to extract metadata and exposes skills to the agent
as context and (optionally) as additional tool registrations.

Skill SKILL.md format:
  # Skill Name
  description: one-line description
  version: 1.0.0
  tools: [tool_name_1, tool_name_2]   (optional)
"""

from __future__ import annotations

import importlib
import importlib.util
import logging
import os
import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)

_SKILLS_DIR = Path(os.environ.get("CLAWTEX_SKILLS_DIR", "./skills")).resolve()


@dataclass
class Skill:
    name: str
    path: Path
    description: str
    version: str = "1.0.0"
    tools: list[str] = field(default_factory=list)
    raw_content: str = ""


class SkillLoader:
    """Discovers and loads skills from the skills directory."""

    def __init__(self, skills_dir: str | Path | None = None) -> None:
        self._dir = Path(skills_dir or _SKILLS_DIR)
        self._skills: dict[str, Skill] = {}

    def load_all(self) -> list[Skill]:
        """Scan the skills directory and load all valid skills."""
        if not self._dir.exists():
            logger.warning("Skills directory not found: %s", self._dir)
            return []

        for skill_dir in sorted(self._dir.iterdir()):
            if not skill_dir.is_dir():
                continue
            skill_md = skill_dir / "SKILL.md"
            if not skill_md.exists():
                continue
            try:
                skill = self._parse_skill(skill_dir, skill_md)
                self._skills[skill.name] = skill
                logger.info("Loaded skill: %s v%s", skill.name, skill.version)
            except Exception as exc:  # noqa: BLE001
                logger.warning("Failed to load skill from %s: %s", skill_dir, exc)

        return list(self._skills.values())

    def _parse_skill(self, skill_dir: Path, skill_md: Path) -> Skill:
        content = skill_md.read_text(encoding="utf-8")
        # Extract name from first heading
        name_match = re.search(r"^#\s+(.+)$", content, re.MULTILINE)
        name = name_match.group(1).strip() if name_match else skill_dir.name

        # Extract description (first non-empty line after heading or line starting with description:)
        desc_match = re.search(r"^description:\s*(.+)$", content, re.MULTILINE | re.IGNORECASE)
        if desc_match:
            description = desc_match.group(1).strip()
        else:
            # Fall back: first paragraph after the title
            lines = [l.strip() for l in content.split("\n") if l.strip() and not l.startswith("#")]
            description = lines[0] if lines else "No description."

        # Extract version
        ver_match = re.search(r"^version:\s*(.+)$", content, re.MULTILINE | re.IGNORECASE)
        version = ver_match.group(1).strip() if ver_match else "1.0.0"

        # Extract tool list
        tools_match = re.search(r"^tools:\s*\[(.+)\]$", content, re.MULTILINE | re.IGNORECASE)
        tools: list[str] = []
        if tools_match:
            tools = [t.strip() for t in tools_match.group(1).split(",") if t.strip()]

        return Skill(
            name=skill_dir.name,
            path=skill_dir,
            description=description,
            version=version,
            tools=tools,
            raw_content=content,
        )

    def get(self, name: str) -> Skill | None:
        return self._skills.get(name)

    def all(self) -> list[Skill]:
        return list(self._skills.values())

    def to_context_block(self) -> str:
        """Return a formatted string listing available skills for system prompt injection."""
        if not self._skills:
            return ""
        lines = ["## Available Skills\n"]
        for skill in self._skills.values():
            lines.append(f"- **{skill.name}** — {skill.description}")
        return "\n".join(lines)
