"""Lazy skill loading tool inspired by OpenCode."""

from __future__ import annotations

from pathlib import Path

from pydantic import BaseModel, Field

from yier_agents.src.skill import SkillCatalog
from yier_agents.src.tool import Tool, ToolContext, ToolOutput


class SkillLoadParams(BaseModel):
    """Parameters for the skill loading tool."""

    name: str = Field(description="The name of the skill to load.")


class SkillLoadTool(Tool[SkillLoadParams]):
    """Built-in tool that loads one discovered skill into the conversation."""

    def __init__(self, catalog: SkillCatalog, file_limit: int = 10):
        self.catalog = catalog
        self.file_limit = file_limit

        async def execute(params: SkillLoadParams, ctx: ToolContext) -> ToolOutput:
            return self._execute(params)

        super().__init__(
            name="skill_load",
            description=self._build_description(),
            parameters=SkillLoadParams,
            execute=execute,
        )

    def _build_description(self) -> str:
        if self.catalog.is_empty():
            return (
                "Load a specialized skill that provides domain-specific instructions "
                "and workflows. No skills are currently available."
            )

        return "\n".join(
            [
                "Load a specialized skill that provides domain-specific instructions and workflows.",
                "",
                "When a task matches one of the available skills below, use this tool to load the full skill instructions.",
                "",
                "The loaded skill includes its SKILL.md content, a base directory, and a sampled file list.",
                "Relative paths mentioned by the skill are resolved from that base directory.",
                "",
                self.catalog.format(verbose=False),
            ]
        )

    def _execute(self, params: SkillLoadParams) -> ToolOutput:
        skill = self.catalog.get(params.name)
        if skill is None:
            available = ", ".join(item.name for item in self.catalog.list()) or "none"
            raise ValueError(f'Skill "{params.name}" not found. Available skills: {available}')

        sampled_files = _sample_skill_files(skill.directory, limit=self.file_limit)
        file_lines = "\n".join(f"<file>{file_path}</file>" for file_path in sampled_files)

        content = "\n".join(
            [
                f'<skill_content name="{skill.name}">',
                f"# Skill: {skill.name}",
                "",
                skill.content,
                "",
                f"Base directory for this skill: {skill.directory.resolve().as_uri()}",
                "Relative paths in this skill (for example scripts/ or references/) are relative to this base directory.",
                "Note: the file list below is sampled.",
                "",
                "<skill_files>",
                file_lines,
                "</skill_files>",
                "</skill_content>",
            ]
        )

        return ToolOutput(
            content=content,
            metadata={
                "name": skill.name,
                "dir": str(skill.directory),
            },
        )


def _sample_skill_files(directory: Path, limit: int) -> list[str]:
    sampled: list[str] = []

    for file_path in sorted(directory.rglob("*")):
        if not file_path.is_file():
            continue
        if file_path.name == "SKILL.md":
            continue

        sampled.append(str(file_path.resolve()))
        if len(sampled) >= limit:
            break

    return sampled
