import json
import shutil
from pathlib import Path

from pydantic_ai import Agent, ModelRetry, RunContext
from pydantic_ai.models import Model

from app.agent.deps import Deps

from .agent import build_skill_creation_agent
from .render import render_skill_draft
from .types import KebabCase, NonEmptyString, SkillCreationDeps, SkillDraft, SkillSpec

CREATE_PROMPT = """
# Planejamento da Skill
```markdown
{plan}
```

# Rascunho do SKILL.md
```markdown
{initial_draft}
```
""".strip()

UPDATE_PROMPT = """
# Estado Atual da Skill
```json
{current_state}
```

# Plano de Atualização
```markdown
{plan}
```
""".strip()


def load_skill_meta(skill_dir: Path) -> SkillSpec | None:
    meta_path = skill_dir / "meta.json"
    if not meta_path.exists():
        return None
    data = json.loads(meta_path.read_text(encoding="utf-8"))
    return SkillSpec.model_validate(data)


def configure_skill_creation_toolset(
    agent: Agent[Deps, str],
    model: Model,
) -> Agent[Deps, str]:
    skill_creation_agent = build_skill_creation_agent(model)

    @agent.tool
    async def create_skill(
        ctx: RunContext[Deps],
        plan: str,
        name: KebabCase,
        description: NonEmptyString,
    ) -> str:
        """Cria uma nova skill conforme o plano fornecido.

        Args:
            plan: Objetivos, motivos e meios (o quê, por quê e como)
            name: Nome da skill em kebab-case
            description: Descrição curta
        """
        initial_message = CREATE_PROMPT.format(
            plan=plan,
            initial_draft=render_skill_draft(
                name=name,
                description=description,
                scripts=[],
            ),
        )

        deps = SkillCreationDeps(
            skills_directory=ctx.deps.skills_dir,
            skill_draft=SkillDraft(
                name=name,
                description=description,
                scripts=[],
            ),
            is_update=False,
        )

        result = await skill_creation_agent.run(initial_message, deps=deps)
        return result.output

    @agent.tool
    async def update_skill(
        ctx: RunContext[Deps],
        name: KebabCase,
        plan: str,
    ) -> str:
        """Atualiza uma skill existente conforme o plano fornecido.

        Args:
            plan: Objetivos, motivos e meios (o quê, por quê e como)
            name: Nome da skill em kebab-case
        """
        skill_dir = ctx.deps.skills_dir / name
        if not skill_dir.exists():
            raise ModelRetry(f"A skill '{name}' não existe e não pode ser atualizada.")

        current_state = load_skill_meta(skill_dir)
        if not current_state:
            raise ModelRetry(f"A skill '{name}' não tem um 'meta.json' válido para atualização.")

        initial_message = UPDATE_PROMPT.format(
            current_state=current_state.model_dump_json(
                indent=2,
                ensure_ascii=False,
            ),
            plan=plan,
        )

        deps = SkillCreationDeps(
            skills_directory=ctx.deps.skills_dir,
            skill_draft=SkillDraft(
                name=name,
                description=current_state.description,
                scripts=current_state.scripts,
            ),
            is_update=True,
        )

        result = await skill_creation_agent.run(initial_message, deps=deps)
        return result.output

    @agent.tool
    def delete_skill(ctx: RunContext[Deps], name: KebabCase) -> str:
        """Remove uma skill. Só é possível remover skills criadas pelo próprio
        usuário — skills globais não podem ser removidas por esta ferramenta.

        Args:
            name: Nome da skill em kebab-case
        """
        skill_dir = ctx.deps.skills_dir / name
        if not skill_dir.exists():
            raise ModelRetry(f"A skill '{name}' não existe ou não pode ser removida.")
        shutil.rmtree(skill_dir)
        return f"Skill '{name}' removida com sucesso."

    return agent
