"""skills/ ディレクトリのスキャン & SKILL.md パース."""

from __future__ import annotations

import re
from pathlib import Path

import yaml

from .types import SkillMeta, SkillResource

# SKILL.md で許容するリソース拡張子
RESOURCE_EXTENSIONS = {".md", ".json", ".yaml", ".yml", ".csv", ".xml", ".txt"}

# スキル名パターン (agentskills.io 仕様)
SKILL_NAME_PATTERN = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")


def parse_skill_md(content: str) -> tuple[dict, str]:
    """SKILL.md の YAML frontmatter と Markdown 本文を分離・解析する.

    Args:
        content: SKILL.md の全テキスト.

    Returns:
        (frontmatter_dict, markdown_body) のタプル.
    """
    # --- で囲まれた YAML frontmatter を抽出
    if content.startswith("---"):
        parts = content.split("---", 2)
        if len(parts) >= 3:
            try:
                frontmatter = yaml.safe_load(parts[1]) or {}
            except yaml.YAMLError:
                frontmatter = {}
            body = parts[2].strip()
            return frontmatter, body

    return {}, content.strip()


def discover_resources(skill_path: Path) -> list[SkillResource]:
    """スキルディレクトリ配下のリソースファイルを発見する.

    SKILL.md を除く、許可された拡張子のファイルを再帰的に探索する。
    シンボリックリンクによるパストラバーサルを防止する。

    Args:
        skill_path: スキルディレクトリのパス.

    Returns:
        発見されたリソースのリスト.
    """
    resources: list[SkillResource] = []
    resolved_root = skill_path.resolve()

    for file_path in sorted(skill_path.rglob("*")):
        if not file_path.is_file():
            continue
        if file_path.name == "SKILL.md":
            continue
        if file_path.suffix.lower() not in RESOURCE_EXTENSIONS:
            continue

        # シンボリックリンクによるパストラバーサル防止
        resolved = file_path.resolve()
        if not str(resolved).startswith(str(resolved_root)):
            continue

        # スキルディレクトリからの相対パスをリソース名に使用
        rel = file_path.relative_to(skill_path)
        resources.append(
            SkillResource(
                name=str(rel),
                path=str(resolved),
            )
        )

    return resources


def discover_skills(
    path: str | Path,
    max_depth: int | None = 3,
) -> list[SkillMeta]:
    """ディレクトリを走査し、SKILL.md を発見してスキル一覧を返す.

    Args:
        path: 検索対象ディレクトリ.
        max_depth: 最大探索深度. None で無制限.

    Returns:
        発見されたスキルのリスト.
    """
    root = Path(path).resolve()
    if not root.is_dir():
        return []

    skills: list[SkillMeta] = []

    # depth-limited glob でSKILL.md を探索
    skill_files = _find_skill_files(root, max_depth)

    for skill_file in skill_files:
        try:
            content = skill_file.read_text(encoding="utf-8")
        except (OSError, UnicodeDecodeError):
            continue

        frontmatter, body = parse_skill_md(content)
        name = frontmatter.get("name", "")
        description = frontmatter.get("description", "")

        if not name:
            # name が無い場合はディレクトリ名をフォールバック
            name = skill_file.parent.name

        skill_dir = skill_file.parent
        resources = discover_resources(skill_dir)

        skills.append(
            SkillMeta(
                name=name,
                description=description,
                path=str(skill_dir),
                content=body,
                resources=resources,
            )
        )

    return skills


def _find_skill_files(root_dir: Path, max_depth: int | None) -> list[Path]:
    """depth-limited で SKILL.md を探索.

    Args:
        root_dir: ルートディレクトリ.
        max_depth: 最大探索深度.

    Returns:
        SKILL.md ファイルパスのリスト.
    """
    results: list[Path] = []

    if max_depth is None:
        # 無制限
        results = sorted(root_dir.rglob("SKILL.md"))
    else:
        # 深度制限付き glob
        for depth in range(max_depth + 1):
            pattern = "/".join(["*"] * depth + ["SKILL.md"])
            results.extend(root_dir.glob(pattern))
        results = sorted(set(results))

    return results
