"""Skill discovery and reading tools."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Any

from memnixa.skills import SkillEntry
from memnixa.tools.base import Tool, paginate_items, paginate_text


@dataclass(slots=True)
class ListSkillsTool(Tool):
    """List available local skills."""

    skills: list[SkillEntry]
    name: str = "skill_list"
    description: str = (
        "List available local skills and their descriptions before selecting one to read."
    )
    parameters: dict[str, Any] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        self.parameters = {
            "type": "object",
            "additionalProperties": False,
            "properties": {
                "query": {"type": "string"},
                "page": {"type": "integer", "minimum": 1},
                "page_size": {"type": "integer", "minimum": 1, "maximum": 100},
            },
        }

    def execute(self, arguments: dict[str, Any]):
        query = str(arguments.get("query") or "").strip().lower()
        rows = [
            {
                "skill_id": skill.skill_id,
                "name": skill.name,
                "description": skill.description,
                "source": skill.source,
                "location": str(skill.file_path),
            }
            for skill in self.skills
            if not query
            or query in skill.skill_id.lower()
            or query in skill.name.lower()
            or query in skill.description.lower()
        ]
        page = int(arguments.get("page") or 1)
        page_size = int(arguments.get("page_size") or 20)
        try:
            items, pagination = paginate_items(rows, page=page, page_size=page_size)
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))
        return self.success(
            data={
                "query": query,
                "skills": items,
            },
            meta={"pagination": pagination},
        )


@dataclass(slots=True)
class ReadSkillTool(Tool):
    """Read one skill file."""

    skills: list[SkillEntry]
    name: str = "skill_read"
    description: str = (
        "Read SKILL.md or another file bundled inside a selected skill directory."
    )
    parameters: dict[str, Any] = None  # type: ignore[assignment]

    def __post_init__(self) -> None:
        self.parameters = {
            "type": "object",
            "additionalProperties": False,
            "properties": {
                "skill_id": {"type": "string", "minLength": 1},
                "path": {"type": "string"},
                "page": {"type": "integer", "minimum": 1},
                "page_size": {"type": "integer", "minimum": 256, "maximum": 16000},
            },
            "required": ["skill_id"],
        }

    def execute(self, arguments: dict[str, Any]):
        skill_id = str(arguments.get("skill_id") or "").strip().lower()
        skill = next((item for item in self.skills if item.skill_id == skill_id), None)
        if skill is None:
            return self.failure("skill_not_found", f"Skill '{skill_id}' was not found.")
        relative_path = str(arguments.get("path") or "SKILL.md").strip() or "SKILL.md"
        try:
            target = _resolve_skill_path(skill.base_dir, relative_path)
        except ValueError as exc:
            return self.failure("invalid_path", str(exc))
        if not target.exists() or not target.is_file():
            return self.failure(
                "not_found",
                f"File '{relative_path}' does not exist in skill '{skill.skill_id}'.",
            )
        content = target.read_text(encoding="utf-8")
        page = int(arguments.get("page") or 1)
        page_size = int(arguments.get("page_size") or 4000)
        try:
            page_content, pagination = paginate_text(
                content,
                page=page,
                page_size=page_size,
            )
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))
        return self.success(
            data={
                "skill_id": skill.skill_id,
                "name": skill.name,
                "path": str(target.relative_to(skill.base_dir)),
                "content": page_content,
                "location": str(target),
            },
            meta={"pagination": pagination},
        )


def _resolve_skill_path(base_dir: Path, raw_path: str) -> Path:
    candidate = (base_dir / raw_path).resolve()
    base_resolved = base_dir.resolve()
    if base_resolved not in candidate.parents and candidate != base_resolved:
        raise ValueError("path escapes the skill directory")
    return candidate
