"""Tests for skill store core — validation, config, registry, installer."""

from __future__ import annotations

import json
from unittest.mock import MagicMock, patch

import pytest


class TestValidation:
    def test_valid_names(self):
        from icarus.skills.validation import validate_skill_name

        for name in ["pdf-tools", "a", "my-skill-123"]:
            assert validate_skill_name(name)[0]

    def test_rejects_bad_names(self):
        from icarus.skills.validation import validate_skill_name

        for name in ["", "a" * 65, "../evil", "MySkill", "-bad", "bad-"]:
            assert not validate_skill_name(name)[0]

    def test_path_escape(self, tmp_path):
        from icarus.skills.validation import validate_skill_path

        ok, _ = validate_skill_path(
            tmp_path / "skills" / ".." / "evil", tmp_path / "skills"
        )
        assert not ok


class TestSkillsConfig:
    def test_default_when_missing(self, tmp_path):
        from icarus.skills.registry_config import SkillsConfig

        config = SkillsConfig.load(tmp_path / "nope.toml")
        assert config.registries[0].name == "icarus"

    def test_roundtrip(self, tmp_path):
        from icarus.skills.registry_config import RegistryEntry, SkillsConfig

        path = tmp_path / "config.toml"
        SkillsConfig(registries=[RegistryEntry("t", "github:t/t")]).save(path)
        assert SkillsConfig.load(path).registries[0].url == "github:t/t"

    def test_add_remove(self):
        from icarus.skills.registry_config import RegistryEntry, SkillsConfig

        c = SkillsConfig(registries=[RegistryEntry("a", "github:a/a")])
        c.add_registry(RegistryEntry("b", "github:b/b"))
        assert len(c.registries) == 2
        c.remove_registry("b")
        assert len(c.registries) == 1
        with pytest.raises(ValueError):
            c.remove_registry("nope")

    def test_preserves_other_sections(self, tmp_path):
        import tomllib

        import tomli_w
        from icarus.skills.registry_config import RegistryEntry, SkillsConfig

        path = tmp_path / "config.toml"
        with path.open("wb") as f:
            tomli_w.dump({"models": {"default": "anthropic:claude"}}, f)

        SkillsConfig(registries=[RegistryEntry("x", "github:x/x")]).save(path)
        with path.open("rb") as f:
            assert tomllib.load(f)["models"]["default"] == "anthropic:claude"


class TestRegistry:
    def test_parse_url(self):
        from icarus.skills.registry import _parse_github_url

        assert _parse_github_url("github:o/r") == ("o", "r")

    def test_parse_url_invalid(self):
        from icarus.skills.registry import RegistryError, _parse_github_url

        with pytest.raises(RegistryError):
            _parse_github_url("https://github.com/x/y")

    @patch("icarus.skills.registry.urllib.request.urlopen")
    def test_fetch_index(self, mock_urlopen):
        from icarus.skills.registry import fetch_index
        from icarus.skills.registry_config import RegistryEntry

        mock_resp = MagicMock()
        mock_resp.read.return_value = json.dumps({"skills": [
            {"name": "pdf", "description": "PDF tools", "version": "1.0"},
        ]}).encode()
        mock_resp.__enter__ = lambda s: s
        mock_resp.__exit__ = MagicMock(return_value=False)
        mock_urlopen.return_value = mock_resp

        result = fetch_index(RegistryEntry("test", "github:t/r"))
        assert result[0].name == "pdf"


class TestInstaller:
    @patch("icarus.skills.installer.fetch_index")
    @patch("icarus.skills.installer.SkillsConfig")
    def test_search(self, mock_cfg, mock_fetch):
        from icarus.skills.installer import search_skills
        from icarus.skills.registry import SkillIndexEntry
        from icarus.skills.registry_config import RegistryEntry

        mock_cfg.load.return_value = MagicMock(
            registries=[RegistryEntry("t", "github:t/t")]
        )
        mock_fetch.return_value = [
            SkillIndexEntry("pdf", "PDF tools", "1.0", ["pdf"]),
            SkillIndexEntry("web", "Web search", "1.0", []),
        ]
        assert len(search_skills("pdf")) == 1

    @patch("icarus.skills.installer.fetch_index")
    @patch("icarus.skills.installer.fetch_skill_files")
    @patch("icarus.skills.installer.SkillsConfig")
    @patch("icarus.config.app_config.Settings")
    def test_install(self, mock_settings, mock_cfg, mock_fetch, mock_idx, tmp_path):
        from icarus.skills.installer import install_skill
        from icarus.skills.registry import SkillIndexEntry
        from icarus.skills.registry_config import RegistryEntry

        skills_dir = tmp_path / "skills"
        skills_dir.mkdir()
        mock_settings.ensure_plugin_skills_dir.return_value = skills_dir
        mock_cfg.load.return_value = MagicMock(
            registries=[RegistryEntry("t", "github:t/t")]
        )
        mock_fetch.return_value = {
            "SKILL.md": b"# PDF", "helper.py": b"print(1)",
        }
        mock_idx.return_value = [SkillIndexEntry("pdf", "", "1.0")]

        r = install_skill("pdf")
        assert r.name == "pdf"
        assert (skills_dir / "pdf" / "SKILL.md").exists()
        assert (skills_dir / "pdf" / ".registry.json").exists()

    @patch("icarus.config.app_config.Settings.get_plugins_base_dir")
    @patch("icarus.skills.installer._user_skills_dir")
    def test_uninstall(self, mock_dir, mock_plugins_base, tmp_path):
        from icarus.skills.installer import uninstall_skill

        skills_dir = tmp_path / "skills"
        (skills_dir / "pdf").mkdir(parents=True)
        mock_dir.return_value = skills_dir
        mock_plugins_base.return_value = tmp_path / "no_plugins"
        uninstall_skill("pdf")
        assert not (skills_dir / "pdf").exists()

    @patch("icarus.skills.installer._user_skills_dir")
    def test_list_installed(self, mock_dir, tmp_path):
        from icarus.skills.installer import list_installed

        skills_dir = tmp_path / "skills"
        (skills_dir / "pdf").mkdir(parents=True)
        (skills_dir / "pdf" / ".registry.json").write_text(
            json.dumps({"registry": "t", "version": "1.0", "installed_at": ""})
        )
        (skills_dir / "local").mkdir()  # no manifest
        mock_dir.return_value = skills_dir

        assert len(list_installed()) == 1


class TestCLIImport:
    def test_validation_reexport(self):
        from icarus_cli.skills_commands import _validate_name

        assert _validate_name("ok")[0]
