"""SkillsMixin: Enumerate available skills for Claude and Codex agents.

Skills are agent-global (not session-specific), loaded from well-known
filesystem locations for each agent type.
"""

import json
from pathlib import Path


class SkillsMixin:
    """Mixin for enumerating agent skills for autocomplete."""

    def _serve_skills(self, agent: str) -> None:
        """Serve autocomplete config for an agent type.

        Args:
            agent: Agent type ('claude' or 'codex')

        Response JSON:
            {trigger: '/' or '$', skills: [{name, description}, ...]}
        """
        if agent == "codex":
            trigger = "$"
            skills = self._enumerate_codex_skills()
        else:  # Default to claude
            trigger = "/"
            skills = self._enumerate_claude_skills()

        # Sort alphabetically by name (case-insensitive)
        skills.sort(key=lambda s: s["name"].lower())

        self._send_json(200, {"trigger": trigger, "skills": skills})

    def _enumerate_claude_skills(self) -> list[dict]:
        """Enumerate Claude skills from ~/.claude/skills/.

        Checks SKILL.md (canonical) first, then falls back to skill.md,
        prompt.md, README.md for description extraction. Parses YAML
        frontmatter if present to extract the description field.

        Returns:
            List of {name: str, description: str} dicts.
            Empty list if directory doesn't exist or enumeration fails.
        """
        skills = []
        skills_dir = Path.home() / ".claude/skills"

        if not skills_dir.exists():
            return skills

        for skill_dir in skills_dir.iterdir():
            if not skill_dir.is_dir() or skill_dir.name.startswith("."):
                continue

            description = ""
            # Check files in priority order
            for md_name in ["SKILL.md", "skill.md", "prompt.md", "README.md"]:
                md_file = skill_dir / md_name
                if md_file.exists():
                    try:
                        content = md_file.read_text()
                        description = self._extract_description(content)
                        if description:
                            break
                    except OSError:
                        pass

            skills.append({
                "name": skill_dir.name,
                "description": description or f"Skill: {skill_dir.name}",
            })

        return skills

    def _extract_description(self, content: str) -> str:
        """Extract description from markdown content.

        Handles YAML frontmatter (looks for 'description:' field) and
        falls back to first meaningful line after frontmatter.
        """
        lines = content.splitlines()
        if not lines:
            return ""

        # Check for YAML frontmatter
        frontmatter_end = 0
        if lines[0].strip() == "---":
            for i, line in enumerate(lines[1:], start=1):
                stripped = line.strip()
                if stripped == "---":
                    frontmatter_end = i + 1
                    break
                # Look for description field in frontmatter
                if stripped.startswith("description:"):
                    # Extract value after colon
                    desc = stripped[len("description:"):].strip()
                    # Remove quotes if present
                    if desc.startswith('"') and desc.endswith('"'):
                        desc = desc[1:-1]
                    elif desc.startswith("'") and desc.endswith("'"):
                        desc = desc[1:-1]
                    # Handle YAML multi-line indicators (>- or |-)
                    if desc in (">-", "|-", ">", "|", ""):
                        # Multi-line: read the next indented line
                        if i + 1 < len(lines):
                            next_line = lines[i + 1].strip()
                            if next_line and not next_line.startswith("---"):
                                return next_line[:100]
                    elif desc:
                        return desc[:100]

        # Fall back to first meaningful line after frontmatter
        for line in lines[frontmatter_end:]:
            stripped = line.strip()
            # Skip empty lines, headers, comments, and frontmatter delimiters
            if stripped and not stripped.startswith("#") and not stripped.startswith("<!--") and stripped != "---":
                return stripped[:100]

        return ""

    def _enumerate_codex_skills(self) -> list[dict]:
        """Enumerate Codex skills from cache and user directory.

        Sources:
            - ~/.codex/vendor_imports/skills-curated-cache.json (curated)
            - ~/.codex/skills/*/ (user-installed)

        Note: No deduplication — if curated and user skills share a name,
        both appear in the list (per plan Known Limitations).

        Returns:
            List of {name: str, description: str} dicts.
            Empty list if no skills found.
        """
        skills = []

        # 1. Curated skills from cache
        cache_file = Path.home() / ".codex/vendor_imports/skills-curated-cache.json"
        if cache_file.exists():
            try:
                data = json.loads(cache_file.read_text())
                for skill in data.get("skills", []):
                    # Use 'id' preferentially, fall back to 'name'
                    name = skill.get("id") or skill.get("name", "")
                    # Use 'shortDescription' preferentially, fall back to 'description'
                    desc = skill.get("shortDescription") or skill.get("description", "")
                    if name:
                        skills.append({
                            "name": name,
                            "description": desc[:100] if desc else f"Skill: {name}",
                        })
            except (json.JSONDecodeError, OSError):
                # Continue without curated skills on parse error
                pass

        # 2. User-installed skills
        user_skills_dir = Path.home() / ".codex/skills"
        if user_skills_dir.exists():
            for skill_dir in user_skills_dir.iterdir():
                if not skill_dir.is_dir() or skill_dir.name.startswith("."):
                    continue

                description = ""
                # Check SKILL.md for description
                skill_md = skill_dir / "SKILL.md"
                if skill_md.exists():
                    try:
                        content = skill_md.read_text()
                        description = self._extract_description(content)
                    except OSError:
                        pass

                skills.append({
                    "name": skill_dir.name,
                    "description": description or f"User skill: {skill_dir.name}",
                })

        return skills
