from __future__ import annotations

import json
from pathlib import Path

from openclaw_lite.skills import SkillManager, SkillRegistry, create_skill, update_skill
from openclaw_lite.skills.loader import load_skill


def test_load_skill_manifest_and_entrypoint(tmp_path: Path) -> None:
    skill_dir = create_skill(
        tmp_path,
        name="hello-world",
        description="Greets the user",
        instructions="# Hello skill\n\nUse this for greetings.",
        entrypoint_code=(
            "def register(context):\n"
            "    return {'tools': [{'name': 'say_hello'}], 'prompts': ['hello'], 'metadata': {'ok': True}}\n"
        ),
    )

    loaded = load_skill(skill_dir)

    assert loaded.manifest.name == "hello-world"
    assert loaded.instructions.startswith("# Hello skill")
    assert loaded.export.tools == [{"name": "say_hello"}]
    assert loaded.export.prompts == ["hello"]
    assert loaded.export.metadata == {"ok": True}
    assert loaded.fingerprint


def test_registry_reload_detects_mutations_and_removals(tmp_path: Path) -> None:
    skill_dir = create_skill(tmp_path, name="reload-me", description="Test skill")
    registry = SkillRegistry(tmp_path)

    first = registry.reload()
    assert first.loaded == ["reload-me"]
    assert first.reloaded == []
    assert registry.get("reload-me") is not None

    update_skill(skill_dir, instructions="# Changed\n", create_backup=False)
    second = registry.reload()
    assert second.reloaded == ["reload-me"]

    for path in skill_dir.iterdir():
        path.unlink()
    skill_dir.rmdir()

    third = registry.reload()
    assert third.removed == ["reload-me"]
    assert registry.get("reload-me") is None


def test_create_and_update_skill_with_backup(tmp_path: Path) -> None:
    skill_dir = create_skill(
        tmp_path,
        name="writer",
        description="Writes files",
        with_entrypoint=False,
    )

    manifest_before = json.loads((skill_dir / "skill.json").read_text(encoding="utf-8"))
    assert manifest_before["entrypoint"] is None

    result = update_skill(
        skill_dir,
        description="Writes files better",
        instructions="# Updated\n",
        manifest_updates={"metadata": {"tag": "updated"}},
    )

    manifest_after = json.loads((skill_dir / "skill.json").read_text(encoding="utf-8"))
    assert manifest_after["description"] == "Writes files better"
    assert manifest_after["metadata"] == {"tag": "updated"}
    assert (skill_dir / "SKILL.md").read_text(encoding="utf-8") == "# Updated\n"
    assert result["backup_dir"] is not None
    assert result["backup_dir"].exists()


def test_skill_manager_api(tmp_path: Path) -> None:
    manager = SkillManager({"skills_root": str(tmp_path)})

    created = manager.create_skill(
        name="managed",
        description="Managed skill",
        instructions="# Managed\n",
        entrypoint_code="def register(context):\n    return {'prompts': ['managed']}\n",
    )

    assert created["reload"]["loaded"] == ["managed"]
    assert [status.name for status in manager.list_skills()] == ["managed"]
    assert manager.get_system_prompt_fragments() == ["# Managed\n", "managed"]

    updated = manager.update_skill(name="managed", instructions="# Updated\n")
    assert updated["backup_dir"] is not None
    summary = manager.reload_if_needed()
    assert summary.loaded == []
    assert any(skill["name"] == "managed" for skill in manager.list_skills())
