"""Workspace and managed skill discovery helpers."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from memnixa.config import get_memnixa_home


@dataclass(frozen=True, slots=True)
class SkillEntry:
    """One discovered skill entry."""

    skill_id: str
    name: str
    description: str
    file_path: Path
    base_dir: Path
    source: str


def discover_skills(workspace: Path) -> list[SkillEntry]:
    """Discover skills with precedence similar to OpenClaw's local skill roots."""
    roots = [
        ("workspace", workspace / "skills"),
        ("project_agents", workspace / ".agents" / "skills"),
        ("user_agents", Path.home() / ".agents" / "skills"),
        ("managed", get_memnixa_home() / "skills"),
    ]
    entries: list[SkillEntry] = []
    seen_ids: set[str] = set()
    for source, root in roots:
        entries.extend(_discover_root_skills(root=root, source=source, seen_ids=seen_ids))
    return entries


def build_skills_prompt(skills: list[SkillEntry]) -> str | None:
    """Render the available skill list for the system prompt."""
    if not skills:
        return None
    lines = [
        "## Skills",
        "Before replying: scan <available_skills> <description> entries.",
        "- If exactly one skill clearly applies: call `skill_read` with its `skill_id`, then follow the skill.",
        "- If multiple could apply: choose the most specific one, then read/follow it.",
        "- If none clearly apply: do not read any skill.",
        "Constraints: never read more than one skill up front; only read after selecting.",
        "",
        "<available_skills>",
    ]
    for skill in skills:
        lines.extend(
            [
                "  <skill>",
                f"    <skill_id>{skill.skill_id}</skill_id>",
                f"    <name>{skill.name}</name>",
                f"    <description>{skill.description}</description>",
                f"    <source>{skill.source}</source>",
                f"    <location>{skill.file_path}</location>",
                "  </skill>",
            ]
        )
    lines.append("</available_skills>")
    return "\n".join(lines)


def _discover_root_skills(
    *,
    root: Path,
    source: str,
    seen_ids: set[str],
) -> list[SkillEntry]:
    if not root.exists() or not root.is_dir():
        return []
    root_resolved = root.resolve()
    entries: list[SkillEntry] = []
    for child in sorted(root.iterdir(), key=lambda item: item.name):
        if not child.is_dir():
            continue
        skill_md = child / "SKILL.md"
        if not skill_md.exists() or not skill_md.is_file():
            continue
        resolved_skill_md = skill_md.resolve()
        if root_resolved not in resolved_skill_md.parents:
            continue
        frontmatter = _parse_frontmatter(resolved_skill_md.read_text(encoding="utf-8"))
        skill_id = _normalize_skill_id(str(frontmatter.get("name") or child.name))
        if not skill_id or skill_id in seen_ids:
            continue
        seen_ids.add(skill_id)
        description = str(frontmatter.get("description") or "").strip() or (
            f"Skill instructions from {skill_id}."
        )
        entries.append(
            SkillEntry(
                skill_id=skill_id,
                name=str(frontmatter.get("name") or child.name).strip() or child.name,
                description=description,
                file_path=resolved_skill_md,
                base_dir=child.resolve(),
                source=source,
            )
        )
    return entries


def _parse_frontmatter(content: str) -> dict[str, str]:
    stripped = content.lstrip()
    if not stripped.startswith("---\n"):
        return {}
    lines = stripped.splitlines()
    payload: dict[str, str] = {}
    for line in lines[1:]:
        if line.strip() == "---":
            return payload
        if ":" not in line:
            continue
        key, value = line.split(":", 1)
        payload[key.strip().lower()] = value.strip().strip("\"'")
    return {}


def _normalize_skill_id(value: str) -> str:
    normalized = value.strip().lower().replace(" ", "-").replace("_", "-")
    while "--" in normalized:
        normalized = normalized.replace("--", "-")
    return normalized.strip("-")
