import re
from pathlib import Path

from pydantic_ai import Agent, RunContext
from pydantic_ai_skills import (
    CallableSkillScriptExecutor,
    SkillsDirectory,
    SkillsToolset,
)

from app.agent.deps import Deps

from .scripts import uv_script_executor


def keep_only_docstring_summary(toolset: SkillsToolset) -> SkillsToolset:
    for tool in toolset.tools.values():
        if tool.description:
            if match := re.search(r"<summary>(.*?)</summary>", tool.description, flags=re.DOTALL):
                tool.description = match.group(1).strip()
    return toolset


def build_skills_toolset(
    global_skills_dir: Path,
    user_skills_dir: Path,
    *,
    executor: CallableSkillScriptExecutor | None = None,
) -> SkillsToolset:
    if executor is None:
        executor = CallableSkillScriptExecutor(func=uv_script_executor)
    user_skills_dir.mkdir(parents=True, exist_ok=True)

    skills_toolset = SkillsToolset(
        directories=[
            SkillsDirectory(path=global_skills_dir, script_executor=executor),
            SkillsDirectory(path=user_skills_dir, script_executor=executor),
        ],
        auto_reload=True,
        exclude_tools=["list_skills"],
    )
    return keep_only_docstring_summary(skills_toolset)


def configure_skill_usage_toolset(
    agent: Agent[Deps, str],
    skills_dir: Path,
) -> Agent[Deps, str]:
    executor = CallableSkillScriptExecutor(func=uv_script_executor)
    toolsets_by_user: dict[Path, SkillsToolset] = {}

    def resolve_toolset(ctx: "RunContext[Deps]") -> SkillsToolset:
        user_skills_dir = ctx.deps.skills_dir
        skills_toolset = toolsets_by_user.get(user_skills_dir)
        if skills_toolset is None:
            skills_toolset = build_skills_toolset(
                skills_dir,
                user_skills_dir,
                executor=executor,
            )
            toolsets_by_user[user_skills_dir] = skills_toolset
        return skills_toolset

    @agent.toolset
    def skills_toolset(ctx: "RunContext[Deps]") -> SkillsToolset:
        return resolve_toolset(ctx)

    @agent.instructions
    async def _execute_instructions(ctx: "RunContext[Deps]") -> str | None:
        skills_toolset = resolve_toolset(ctx)
        base = await skills_toolset.get_instructions(ctx)
        if base is None:
            return None
        return f"## Skills\n\n{base}"

    return agent
